Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
9.66% covered (danger)
9.66%
2104 / 21787
33.51% covered (warning)
33.51%
65 / 194
CRAP
0.00% covered (danger)
0.00%
0 / 1
PaymentController
9.66% covered (danger)
9.66%
2104 / 21787
33.51% covered (warning)
33.51%
65 / 194
20756941.61
0.00% covered (danger)
0.00%
0 / 1
 beforeFilter
0.00% covered (danger)
0.00%
0 / 114
0.00% covered (danger)
0.00%
0 / 1
380
 index
100.00% covered (success)
100.00%
25 / 25
100.00% covered (success)
100.00%
1 / 1
2
 getWPPaymentResult
89.43% covered (success)
89.43%
457 / 511
0.00% covered (danger)
0.00%
0 / 1
155.19
 worldpay_error_log_set
95.71% covered (success)
95.71%
134 / 140
0.00% covered (danger)
0.00%
0 / 1
28
 complete
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
4
 pointsComplete
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
1 / 1
2
 callback
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 checkCallBack
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
6
 savePdataLog
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 t_start
100.00% covered (success)
100.00%
38 / 38
100.00% covered (success)
100.00%
1 / 1
5
 charge_company_select
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 z_start
96.91% covered (success)
96.91%
157 / 162
0.00% covered (danger)
0.00%
0 / 1
64
 payment_credit_register_complete
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
4
 coupon_payment_credit_charge_complete
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 payment_credit_charge_complete
100.00% covered (success)
100.00%
58 / 58
100.00% covered (success)
100.00%
1 / 1
7
 payment_credit_retry_complete
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
4
 payment_credit_change_complete
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
5
 handleCreditResponseError
100.00% covered (success)
100.00%
27 / 27
100.00% covered (success)
100.00%
1 / 1
16
 zeuspay
0.00% covered (danger)
0.00%
0 / 2022
0.00% covered (danger)
0.00%
0 / 1
298662
 saveStep
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
2
 corporateZeuspay
0.00% covered (danger)
0.00%
0 / 1196
0.00% covered (danger)
0.00%
0 / 1
89102
 update_card_fail_flg
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
8
 _error_log_set
81.68% covered (success)
81.68%
107 / 131
0.00% covered (danger)
0.00%
0 / 1
32.82
 free_digest_member_t_start
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
3
 coupon_form
100.00% covered (success)
100.00%
80 / 80
100.00% covered (success)
100.00%
1 / 1
15
 payment_credit_register
0.00% covered (danger)
0.00%
0 / 86
0.00% covered (danger)
0.00%
0 / 1
342
 zeus_credit_register
0.00% covered (danger)
0.00%
0 / 166
0.00% covered (danger)
0.00%
0 / 1
756
 checkIfChargedAfterChallenge
13.33% covered (danger)
13.33%
8 / 60
0.00% covered (danger)
0.00%
0 / 1
928.17
 wp_credit_register
0.00% covered (danger)
0.00%
0 / 87
0.00% covered (danger)
0.00%
0 / 1
240
 payment_credit_register_confirm
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 zeus_credit_register_confirm
100.00% covered (success)
100.00%
26 / 26
100.00% covered (success)
100.00%
1 / 1
8
 wp_credit_register_confirm
0.00% covered (danger)
0.00%
0 / 182
0.00% covered (danger)
0.00%
0 / 1
1190
 paypal_payment_credit_register_confirm
100.00% covered (success)
100.00%
20 / 20
100.00% covered (success)
100.00%
1 / 1
2
 paypal_payment_credit_register_process
0.00% covered (danger)
0.00%
0 / 100
0.00% covered (danger)
0.00%
0 / 1
462
 sp_paypal_payment_credit_register_process
100.00% covered (success)
100.00%
34 / 34
100.00% covered (success)
100.00%
1 / 1
9
 wp_credit_register_form
100.00% covered (success)
100.00%
45 / 45
100.00% covered (success)
100.00%
1 / 1
2
 payment_credit_change
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
5
 zeus_credit_change
0.00% covered (danger)
0.00%
0 / 88
0.00% covered (danger)
0.00%
0 / 1
1260
 paypal_payment_credit_change_process
96.15% covered (success)
96.15%
25 / 26
0.00% covered (danger)
0.00%
0 / 1
6
 wp_credit_change
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
1 / 1
6
 wp_credit_change_form
100.00% covered (success)
100.00%
23 / 23
100.00% covered (success)
100.00%
1 / 1
4
 payment_credit_charge
0.00% covered (danger)
0.00%
0 / 28
0.00% covered (danger)
0.00%
0 / 1
42
 zeus_credit_charge
0.00% covered (danger)
0.00%
0 / 329
0.00% covered (danger)
0.00%
0 / 1
6006
 wp_credit_charge
0.00% covered (danger)
0.00%
0 / 64
0.00% covered (danger)
0.00%
0 / 1
380
 payment_credit_charge_confirm
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 retrial_confiscate_coins
100.00% covered (success)
100.00%
41 / 41
100.00% covered (success)
100.00%
1 / 1
14
 zeus_credit_charge_confirm
1.82% covered (danger)
1.82%
1 / 55
0.00% covered (danger)
0.00%
0 / 1
398.58
 wp_credit_charge_confirm
0.54% covered (danger)
0.54%
1 / 186
0.00% covered (danger)
0.00%
0 / 1
1240.35
 paypal_payment_credit_charge_confirm
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
1 / 1
3
 wp_credit_charge_form
0.00% covered (danger)
0.00%
0 / 54
0.00% covered (danger)
0.00%
0 / 1
156
 paypal_payment_credit_charge_process
0.00% covered (danger)
0.00%
0 / 75
0.00% covered (danger)
0.00%
0 / 1
306
 payment_credit_retry
80.00% covered (success)
80.00%
8 / 10
0.00% covered (danger)
0.00%
0 / 1
2.03
 zeus_credit_retry
1.95% covered (danger)
1.95%
4 / 205
0.00% covered (danger)
0.00%
0 / 1
2040.54
 wp_credit_retry
2.13% covered (danger)
2.13%
1 / 47
0.00% covered (danger)
0.00%
0 / 1
147.00
 payment_credit_retry_confirm
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
 zeus_credit_retry_confirm
100.00% covered (success)
100.00%
26 / 26
100.00% covered (success)
100.00%
1 / 1
10
 wp_credit_retry_confirm
0.00% covered (danger)
0.00%
0 / 182
0.00% covered (danger)
0.00%
0 / 1
1122
 paypal_payment_credit_retry_confirm
100.00% covered (success)
100.00%
16 / 16
100.00% covered (success)
100.00%
1 / 1
2
 wp_credit_retry_form
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
6
 paypal_payment_credit_retry_process
77.27% covered (success)
77.27%
17 / 22
0.00% covered (danger)
0.00%
0 / 1
7.58
 checkUser
98.04% covered (success)
98.04%
50 / 51
0.00% covered (danger)
0.00%
0 / 1
28
 formDataValidation
100.00% covered (success)
100.00%
30 / 30
100.00% covered (success)
100.00%
1 / 1
25
 withdraw
0.00% covered (danger)
0.00%
0 / 45
0.00% covered (danger)
0.00%
0 / 1
182
 withdraw_confirm
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
2
 checkToken
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
 unsetToken
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 createPaymentTransaction
0.00% covered (danger)
0.00%
0 / 201
0.00% covered (danger)
0.00%
0 / 1
7310
 getPaymentTransaction
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
3
 mobapp_payment_credit_register_receivable
97.22% covered (success)
97.22%
35 / 36
0.00% covered (danger)
0.00%
0 / 1
9
 mobapp_credit_change
0.00% covered (danger)
0.00%
0 / 67
0.00% covered (danger)
0.00%
0 / 1
600
 mobapp_wp_credit_change
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
6
 mobapp_wp_credit_change_form
0.00% covered (danger)
0.00%
0 / 33
0.00% covered (danger)
0.00%
0 / 1
30
 mobapp_credit_change_form
0.00% covered (danger)
0.00%
0 / 76
0.00% covered (danger)
0.00%
0 / 1
380
 mobapp_paypal_credit_change_process
0.00% covered (danger)
0.00%
0 / 32
0.00% covered (danger)
0.00%
0 / 1
12
 mobapp_credit_retry
0.00% covered (danger)
0.00%
0 / 202
0.00% covered (danger)
0.00%
0 / 1
1892
 mobapp_credit_retry_form
0.00% covered (danger)
0.00%
0 / 97
0.00% covered (danger)
0.00%
0 / 1
306
 mobapp_wp_credit_retry
0.00% covered (danger)
0.00%
0 / 33
0.00% covered (danger)
0.00%
0 / 1
30
 mobapp_wp_credit_retry_form
0.00% covered (danger)
0.00%
0 / 41
0.00% covered (danger)
0.00%
0 / 1
72
 mobapp_wp_credit_retry_confirm
0.00% covered (danger)
0.00%
0 / 182
0.00% covered (danger)
0.00%
0 / 1
992
 mobapp_credit_retry_confirm
0.00% covered (danger)
0.00%
0 / 43
0.00% covered (danger)
0.00%
0 / 1
110
 mobapp_paypal_credit_retry_confirm
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
6
 mobapp_paypal_credit_retry_process
0.00% covered (danger)
0.00%
0 / 29
0.00% covered (danger)
0.00%
0 / 1
156
 mobapp_credit_register_trial_notice
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
2
 mobapp_credit_register
0.00% covered (danger)
0.00%
0 / 109
0.00% covered (danger)
0.00%
0 / 1
182
 mobapp_credit_register_form
0.00% covered (danger)
0.00%
0 / 141
0.00% covered (danger)
0.00%
0 / 1
462
 sp_credit_register_form
0.00% covered (danger)
0.00%
0 / 40
0.00% covered (danger)
0.00%
0 / 1
42
 mobapp_credit_register_confirm
0.00% covered (danger)
0.00%
0 / 25
0.00% covered (danger)
0.00%
0 / 1
56
 mobapp_paypal_credit_register_confirm
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
6
 mobapp_paypal_credit_register_process
0.00% covered (danger)
0.00%
0 / 88
0.00% covered (danger)
0.00%
0 / 1
272
 mobapp_credit_register_notice_to_user
0.00% covered (danger)
0.00%
0 / 138
0.00% covered (danger)
0.00%
0 / 1
1482
 mobapp_credit_register_native_plan
0.00% covered (danger)
0.00%
0 / 89
0.00% covered (danger)
0.00%
0 / 1
420
 mobapp_credit_register_questionnaire
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 mobapp_wp_credit
0.00% covered (danger)
0.00%
0 / 78
0.00% covered (danger)
0.00%
0 / 1
210
 mobapp_wp_credit_register
0.00% covered (danger)
0.00%
0 / 72
0.00% covered (danger)
0.00%
0 / 1
272
 mobapp_wp_credit_register_form
0.00% covered (danger)
0.00%
0 / 28
0.00% covered (danger)
0.00%
0 / 1
12
 mobapp_wp_credit_register_confirm
0.00% covered (danger)
0.00%
0 / 176
0.00% covered (danger)
0.00%
0 / 1
1056
 mobapp_credit_charge
0.00% covered (danger)
0.00%
0 / 288
0.00% covered (danger)
0.00%
0 / 1
4556
 mobapp_credit_charge_form
0.00% covered (danger)
0.00%
0 / 325
0.00% covered (danger)
0.00%
0 / 1
5112
 mobapp_wp_credit_charge
0.00% covered (danger)
0.00%
0 / 60
0.00% covered (danger)
0.00%
0 / 1
342
 mobapp_wp_credit_charge_form
0.00% covered (danger)
0.00%
0 / 57
0.00% covered (danger)
0.00%
0 / 1
210
 mobapp_wp_credit_charge_confirm
0.00% covered (danger)
0.00%
0 / 184
0.00% covered (danger)
0.00%
0 / 1
1190
 mobapp_credit_charge_confirm
0.00% covered (danger)
0.00%
0 / 76
0.00% covered (danger)
0.00%
0 / 1
552
 mobapp_paypal_credit_charge_confirm
0.00% covered (danger)
0.00%
0 / 20
0.00% covered (danger)
0.00%
0 / 1
6
 mobapp_paypal_credit_charge_process
0.00% covered (danger)
0.00%
0 / 76
0.00% covered (danger)
0.00%
0 / 1
210
 mobappSetUpTransaction
0.00% covered (danger)
0.00%
0 / 33
0.00% covered (danger)
0.00%
0 / 1
210
 checkTokenMobapp
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 unsetTokenMobapp
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 getUserData
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
2
 zeus_card_process_mobapp
0.00% covered (danger)
0.00%
0 / 198
0.00% covered (danger)
0.00%
0 / 1
5402
 handleCreditResponseErrorMobapp
100.00% covered (success)
100.00%
32 / 32
100.00% covered (success)
100.00%
1 / 1
18
 failure_family
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 sp_failure_family
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getUserId
0.00% covered (danger)
0.00%
0 / 16
0.00% covered (danger)
0.00%
0 / 1
110
 decodeSendPointData
100.00% covered (success)
100.00%
21 / 21
100.00% covered (success)
100.00%
1 / 1
5
 failureFamily
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
3
 getAndSetCardInfo
100.00% covered (success)
100.00%
30 / 30
100.00% covered (success)
100.00%
1 / 1
12
 setPaymentViewVars
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 failure_settlement
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
2
 mobapp_failure_settlement
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
6
 sp_failure_settlement
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
4
 getWPUserData
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
1 / 1
2
 updatePaymentTransaction
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
42
 getHostedPage
0.00% covered (danger)
0.00%
0 / 319
0.00% covered (danger)
0.00%
0 / 1
8556
 deleteUserToken
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
 memcacheWPPayment
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
9
 memcacheCardType
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 processWPPayment
0.00% covered (danger)
0.00%
0 / 1187
0.00% covered (danger)
0.00%
0 / 1
105300
 mobappGetUserData
0.00% covered (danger)
0.00%
0 / 90
0.00% covered (danger)
0.00%
0 / 1
702
 getRetryPaymentData
0.00% covered (danger)
0.00%
0 / 120
0.00% covered (danger)
0.00%
0 / 1
756
 changePaymentPlanIfTelecomUser
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
4
 notice_coupon_code_plan
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
2
 notice_coupon_code_plan_change
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
2
 complimentaryPlanValidation
100.00% covered (success)
100.00%
24 / 24
100.00% covered (success)
100.00%
1 / 1
5
 updateUserCardCompanyToZeus
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 slackWPErrorPostMsg
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
1
 ifComPlanUser
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
7
 getCorporatePaymentPlan
96.97% covered (success)
96.97%
32 / 33
0.00% covered (danger)
0.00%
0 / 1
10
 mobapp_corporate_register_card
6.25% covered (danger)
6.25%
5 / 80
0.00% covered (danger)
0.00%
0 / 1
226.94
 slackZeusErrorPostMsg
0.00% covered (danger)
0.00%
0 / 23
0.00% covered (danger)
0.00%
0 / 1
6
 processPayPalPayment
0.00% covered (danger)
0.00%
0 / 613
0.00% covered (danger)
0.00%
0 / 1
11772
 addCoinRewardForReenroll
0.00% covered (danger)
0.00%
0 / 45
0.00% covered (danger)
0.00%
0 / 1
182
 paypalSaveBillingAgreement
2.98% covered (danger)
2.98%
9 / 302
0.00% covered (danger)
0.00%
0 / 1
3687.63
 setSupportPayPal
0.00% covered (danger)
0.00%
0 / 42
0.00% covered (danger)
0.00%
0 / 1
272
 sms_questionnaire
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
 restrictForTrialNotConducted
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
20
 zeuspayGetChallenge
0.00% covered (danger)
0.00%
0 / 443
0.00% covered (danger)
0.00%
0 / 1
22952
 reportZeusChallengeResponse
0.00% covered (danger)
0.00%
0 / 258
0.00% covered (danger)
0.00%
0 / 1
5852
 sendZeusResponseSlackMessage
0.00% covered (danger)
0.00%
0 / 14
0.00% covered (danger)
0.00%
0 / 1
12
 processRedirection
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
12
 getAfteeHostedPage
0.00% covered (danger)
0.00%
0 / 238
0.00% covered (danger)
0.00%
0 / 1
3906
 getAfteePaymentResult
0.00% covered (danger)
0.00%
0 / 19
0.00% covered (danger)
0.00%
0 / 1
30
 afteeAuthentication
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
 processAfteePayment
0.00% covered (danger)
0.00%
0 / 721
0.00% covered (danger)
0.00%
0 / 1
33672
 slackAfteePErrorPostMsg
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
2
 handleAfteeAuthenticationSuccess
0.00% covered (danger)
0.00%
0 / 356
0.00% covered (danger)
0.00%
0 / 1
10920
 handleAfteeDirectPaymentSuccess
0.00% covered (danger)
0.00%
0 / 497
0.00% covered (danger)
0.00%
0 / 1
8190
 sendNatGeoEbookPurchaseEmailSlack
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
2
 sendEbookPurchaseEmailSlack
0.00% covered (danger)
0.00%
0 / 82
0.00% covered (danger)
0.00%
0 / 1
380
 isForTrialReenrollment
0.00% covered (danger)
0.00%
0 / 12
0.00% covered (danger)
0.00%
0 / 1
12
 checkZeusChallengeResponse
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
 setPaymentPlanDetails
0.00% covered (danger)
0.00%
0 / 56
0.00% covered (danger)
0.00%
0 / 1
182
 corpIndividualData
0.00% covered (danger)
0.00%
0 / 118
0.00% covered (danger)
0.00%
0 / 1
702
 corporate_change_individual_card_payment
0.00% covered (danger)
0.00%
0 / 15
0.00% covered (danger)
0.00%
0 / 1
20
 corp_user_change_personal_card
0.00% covered (danger)
0.00%
0 / 135
0.00% covered (danger)
0.00%
0 / 1
2070
 paypal_student_discount_user_change_card
0.00% covered (danger)
0.00%
0 / 294
0.00% covered (danger)
0.00%
0 / 1
2550
 student_discount_user_change_card
0.00% covered (danger)
0.00%
0 / 167
0.00% covered (danger)
0.00%
0 / 1
2256
 mobapp_corporate_change_individual_card_payment
0.00% covered (danger)
0.00%
0 / 267
0.00% covered (danger)
0.00%
0 / 1
3306
 processChildReceivablePayment
0.00% covered (danger)
0.00%
0 / 117
0.00% covered (danger)
0.00%
0 / 1
272
 processChildPaypalPayment
0.00% covered (danger)
0.00%
0 / 224
0.00% covered (danger)
0.00%
0 / 1
420
 processChildAfteePayment
0.00% covered (danger)
0.00%
0 / 233
0.00% covered (danger)
0.00%
0 / 1
600
 mobapp_credit_retry_complete
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
6
 setLitePaymentInfoView
0.00% covered (danger)
0.00%
0 / 31
0.00% covered (danger)
0.00%
0 / 1
42
 liteUserAddCoinRewardForReenroll
0.00% covered (danger)
0.00%
0 / 45
0.00% covered (danger)
0.00%
0 / 1
56
 processChangePlan
0.00% covered (danger)
0.00%
0 / 206
0.00% covered (danger)
0.00%
0 / 1
2162
 processChildWithdrawal
0.00% covered (danger)
0.00%
0 / 77
0.00% covered (danger)
0.00%
0 / 1
240
 paypal_payment_change_plan_process
0.00% covered (danger)
0.00%
0 / 566
0.00% covered (danger)
0.00%
0 / 1
4830
 zeus_payment_change_plan
0.00% covered (danger)
0.00%
0 / 89
0.00% covered (danger)
0.00%
0 / 1
210
 payment_credit_register_receivable
0.00% covered (danger)
0.00%
0 / 47
0.00% covered (danger)
0.00%
0 / 1
156
 createCorporateIndividualPayment
0.00% covered (danger)
0.00%
0 / 130
0.00% covered (danger)
0.00%
0 / 1
812
 getDefaultPlanId
100.00% covered (success)
100.00%
23 / 23
100.00% covered (success)
100.00%
1 / 1
7
 selectCorpType
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
4
 createLitePlanTransaction
0.00% covered (danger)
0.00%
0 / 53
0.00% covered (danger)
0.00%
0 / 1
210
 applyCouponPayment
0.00% covered (danger)
0.00%
0 / 73
0.00% covered (danger)
0.00%
0 / 1
756
 setCouponUseData
0.00% covered (danger)
0.00%
0 / 24
0.00% covered (danger)
0.00%
0 / 1
30
 paypalWebhook
0.00% covered (danger)
0.00%
0 / 74
0.00% covered (danger)
0.00%
0 / 1
306
 createChocottoPlanTransaction
0.00% covered (danger)
0.00%
0 / 45
0.00% covered (danger)
0.00%
0 / 1
132
 stripepay
0.00% covered (danger)
0.00%
0 / 32
0.00% covered (danger)
0.00%
0 / 1
72
 stripepay_manual
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 handleStripePaymentResult
0.23% covered (danger)
0.23%
4 / 1777
0.00% covered (danger)
0.00%
0 / 1
200691.66
 stripe_error_log_set
0.00% covered (danger)
0.00%
0 / 119
0.00% covered (danger)
0.00%
0 / 1
650
 slackStripeErrorPostMsg
100.00% covered (success)
100.00%
23 / 23
100.00% covered (success)
100.00%
1 / 1
2
 getStripeHostedPage
0.00% covered (danger)
0.00%
0 / 261
0.00% covered (danger)
0.00%
0 / 1
5402
 sendStripeResponseSlackMessage
0.00% covered (danger)
0.00%
0 / 17
0.00% covered (danger)
0.00%
0 / 1
30
 updateUserToken
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2App::uses('AppController', 'Controller');
3App::uses('Folder', 'Utility');
4App::uses('File', 'Utility');
5
6class PaymentController extends AppController {
7    public $uses = array(
8        'User',
9        'CourseMaster',
10        'PaymentLogs',
11        'UsersCourses',
12        'UsersPoints',
13        'PaymentLog',
14        'LessonOnairsLog',
15        'Payment',
16        'PaymentTransaction',
17        'RecurringLog',
18        'ZPaymentSucceeded',
19        'UsersEmailConfirm',
20        'UsersRegistrationQuestion',
21        'PaymentReceivable',
22        'TextbookSale',
23        'UsersPointHistory',
24        'FamilyPlanList',
25        'UsersPoint',
26        'PaymentPlanPrice',
27        'Currency',
28        'CorporatePaymentMemberReceivable',
29        'Corporate',
30        'UserWithdrawReenrollCampaign',
31        'UserStatusChangeLog',
32        'UsersReferral',
33        'UsersCoupon',
34        'UsersCouponV1',
35        'CoinBox',
36        'ComplimentaryCode',
37        'CorporatesPaymentReceivable',
38        'CorporateDiscountRate',
39        'LessonOnairsLog',
40        'CorporateScheduledDeactivation',
41        'CorporatePaymentIdLog',
42        'NativeOption',
43        'UsersDeactivationEnquate',
44        'LessonSchedule',
45        'FamilyDeactivationLog',
46        'UsersFamilyAccount',
47        'CampaignMaster',
48        'PhoneVerifyCheckLog',
49        'CountryCode',
50        'Timezone',
51        'CorporateActivationManagement',
52        'CorporateActivationManagementLog',
53        'TextbookSalesAddToCartItem',
54        'CorporateCategory',
55        'UsersDetail',
56        'TextbookSalesAddToCartItem',
57        'UserDiscountOptionsTerm',
58        'DiscountOptionsSettlementHistory',
59        'DiscountOptionsPrice',
60        'UserOptionChangeLog',
61        'FileStorage',
62        'Payment',
63        'StudentDiscountApplicationForm',
64        'RyugakuSchoolPayment',
65        'RyugakuAdminEstimateRequest',
66        'ZeusAccountBlock',
67        'IpBlock',
68        'RyugakuAdminEstimateRequestPricing',
69        'ContinuationRewardPoint',
70        'CompCodeUsage'
71    );
72    public $memcache = null;
73    public $helpers = array('Html', 'Form');
74    public $components = array("ZCharge");
75    public function beforeFilter() {
76        parent::beforeFilter();
77        //instantiate slack
78        $this->mySlack = new mySlack();
79        //set slack channel
80        $this->slackChannel = myTools::checkChannel('#nc-settlement', '#nc-settlement-dev');
81        $this->Auth->allow(array(
82            'callback',
83            'zeuspay',
84            'mobapp_credit_change',
85            'mobapp_credit_change_form',
86            'mobapp_credit_change_complete',
87            'mobapp_credit_register',
88            'mobapp_credit_register_form',
89            'mobapp_credit_charge',
90            'mobapp_credit_charge_form',
91            'mobapp_corporate_change_individual_card_payment',
92            'mobapp_corporate_change_individual_card_payment_form',
93            'mobapp_credit_charge_confirm',
94            'mobapp_credit_register_confirm',
95            'mobapp_credit_register_notice_to_user',
96            'mobapp_credit_register_native_plan',
97            'mobapp_credit_register_questionnaire',
98            'mobapp_credit_retry',
99            'mobapp_credit_retry_form',
100            'mobapp_credit_retry_confirm',
101            'mobapp_failure_settlement',
102            'failureFamily',
103            'getWPPaymentResult',
104            'mobapp_wp_credit_change',
105            'mobapp_wp_credit_change_form',
106            'mobapp_wp_credit_retry',
107            'mobapp_wp_credit_retry_form',
108            'mobapp_wp_credit_retry_confirm',
109            'mobapp_wp_credit_charge',
110            'mobapp_wp_credit_charge_form',
111            'mobapp_wp_credit_charge_confirm',
112            'mobapp_wp_credit_register',
113            'mobapp_wp_credit_register_form',
114            'mobapp_wp_credit_register_confirm',
115            'wp_card_has_issue',
116            'getHostedPage',
117            'notice_coupon_code_plan',
118            'notice_coupon_code_plan_change',
119            'mobapp_corporate_register_card',
120            'mobapp_paypal_credit_register_confirm',
121            'mobapp_paypal_credit_register_process',
122            'mobapp_paypal_credit_change_process',
123            'mobapp_paypal_credit_charge_confirm',
124            'mobapp_paypal_credit_charge_process',
125            'mobapp_paypal_credit_retry_confirm',
126            'mobapp_paypal_credit_retry_process',
127            'mobapp_credit_register_trial_notice',
128            'mobapp_wp_credit',
129            'zeuspayGetChallenge',
130            'handleAfteeAuthenticationSuccess',
131            'getAfteePaymentResult',
132            'afteeAuthentication',
133            'getAfteeHostedPage',
134            'handleAfteeDirectPaymentSuccess',
135            'checkZeusChallengeResponse',
136            'reportZeusChallengeResponse',
137            'corp_user_change_personal_card',
138            'mobapp_credit_retry_complete',
139            'processChangePlan',
140            'createCorporateIndividualPayment',
141            'applyCouponPayment',
142            'mobapp_payment_credit_register_receivable',
143            'student_discount_user_change_card',
144            'paypal_student_discount_user_change_card',
145            'paypalWebhook',
146            'stripepay',
147            'getStripeHostedPage',
148            'stripepay_manual'
149        ));
150        $this->set('referer', $this->referer());
151        $this->set('page_css', 'payment');
152        //memcache
153        $this->memcache = new myMemcached();
154
155        $joinNativeOption = (isset($this->request->query['joinNativeOption']) && $this->request->query['joinNativeOption']) ? true : false;
156        $purchaseCoinTextbookNativeOptionAftee = (isset($this->request->params['action']) && $this->request->params['action'] == 'handleAfteeDirectPaymentSuccess') ? true : false;
157
158        // redirect to failure_family if family plan
159        if (!empty($this->sharedUserData['User']['parent_id']) && $this->action != 'failure_family' && !$joinNativeOption && !$purchaseCoinTextbookNativeOptionAftee) {
160            return $this->redirect(myTools::getUrl() . '/payment/failure_family');
161        } elseif ($this->parentId && $this->action != 'failureFamily' && !$joinNativeOption && !$purchaseCoinTextbookNativeOptionAftee) {
162            return $this->redirect(myTools::getUrl() . '/user/mobapp/payment/failure_family?'  . $_SERVER['QUERY_STRING']);    
163        }
164
165        $action = $this->params['action'];
166        $mobappActions = array(
167            'mobapp_credit_change',
168            'mobapp_credit_change_form',
169            'mobapp_credit_retry',
170            'mobapp_credit_retry_confirm',
171            'mobapp_credit_retry_form',
172            'mobapp_credit_register_form',
173            'mobapp_credit_register_confirm',
174            'mobapp_credit_charge',
175            'mobapp_credit_charge_form',
176            'mobapp_corporate_change_individual_card_payment',
177            'mobapp_corporate_change_individual_card_payment_form',
178            'mobapp_credit_charge_confirm'
179        );
180
181        $mobappFirstPages = array('mobapp_credit_retry', 'mobapp_credit_change', 'mobapp_credit_register', 'mobapp_credit_charge', 'mobapp_credit_charge','corporate_change_individual_card_payment');
182        if (in_array($action, $mobappFirstPages)) {
183            myTools::setTokenSession();
184        }
185
186        //*set $_GET['token'] if missing for mobapp
187        myTools::checkMobappToken($action, $mobappActions);
188
189        //fetch monthly detail
190        $monthly_price = $this->User->getMonthlyPayment(array(
191            'query' => $this->request->query,
192            'cookie' => $this->Cookie->read('currency_cookie')
193        ));
194
195        $this->set($monthly_price);
196        //save currency in cookie
197        $this->Cookie->write('currency_cookie', $monthly_price['currency']);
198        
199        // - NC_8454 show maintenance error when it's zeus maintenance time
200        $zeusMaintenance = false;
201        if (myTools::zeusMaintenancePeriod()){
202            $zeusMaintenance = true;
203        }
204        $this->set('zeus_maintenance', $zeusMaintenance);
205
206        // check if allowed aftee
207        $enableAftee = (isset($this->localizeDir) && $this->localizeDir == 'zh-tw') ? 1 : 0;
208        if (isset($this->sharedUserData['User']['currency_code']) && $this->sharedUserData['User']['currency_code'] != 'TWD') {
209            $enableAftee = 0;
210        }
211        $this->set('enableAftee', false);
212
213    }
214
215    public function index() {
216        $this->savePdataLog(1);
217        $data = $this->checkCallBack();
218        if ($data) {
219            //insert db payment log
220            $this->Payment->create();
221            $this->Payment->set(array(
222                'user_id' => $this->Auth->user('id'),
223                'type_id' => 1,
224                'pay_kbn' => 1,
225                'reference_id' => $data['txn_id'],
226                'amount' => $data['mc_gross'],
227                'course_id' => $data['item_number1'],
228                'param1' => json_encode($data)
229            ));
230            $this->Payment->save();
231
232            //insert db points
233            $courseMasterData = $this->CourseMaster->findById($data['item_number1']);
234            $courseMaster = $courseMasterData['CourseMaster'];
235            // NC-5007
236            $pointParams = array(
237                'userId' => $this->Auth->user('id'),
238                'point' => $courseMaster['add_point'],
239                'kbn' => 2,
240                'kbnType' => 1, // add coin
241                'coinType' => 2, // service point
242            );
243            $this->UsersPoint->performPointTransaction($pointParams);
244
245            //thank you page
246            return $this->redirect(myTools::getUrl() . '/payment/points/complete');
247        }
248    }
249
250    /**
251     * NC-4770: Receive the payment result from worldpay
252     * @param $_POST data
253     */
254    public function getWPPaymentResult() {
255        $this->autoRender = $this->autoLayout = false;
256
257        $this->log('fetched wp result --> ' . json_encode($_POST), 'wp_debug');
258
259        // get data
260        $data = $_POST;
261
262        // return if empty data
263        if (!$data) {
264            $this->log(__METHOD__ . ' Worldpay: Empty kickback data --> ' . json_encode($data), 'wp_debug');
265            return "[OK]"; 
266            //NJ-69126 exit; I used return to force Stop Unit Test to process below and if use Exit it will stop the whole process also
267        }
268
269        // set variables
270        $orderCode = isset($data['OrderCode']) ? $data['OrderCode'] : null;
271        $paymentStatusName = isset($data['PaymentStatus']) ? $data['PaymentStatus'] : '';
272        $dataJson = json_encode($data);
273
274        // get payment transaction data 
275        $paymentTransactionData = $this->PaymentTransaction->getWPPaymentTransaction($orderCode);
276        $userId = $paymentTransactionData['user_id'] ?? null;
277
278        $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - fetched wp result --> ' . json_encode($_POST), 'error');
279
280        // if pending payment transaction does not exist remove status condition to check if has failed transation to override it
281        if (!$paymentTransactionData && $paymentStatusName == Configure::read('worldpay.payment_status_authorised')) {
282            $paymentTransactionData = $this->PaymentTransaction->getWPPaymentTransaction2($orderCode);
283            $userId = $paymentTransactionData['user_id'] ?? null;
284        }
285
286        // return if payment transaction does not exist
287        if (!$paymentTransactionData) {
288            $msg = 'Payment transaction does not exist.';
289            $this->log(__METHOD__ . ' ' . $msg . ' kickback data -->' . $dataJson, 'wp_debug');
290            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' kickback data -->'. $dataJson, 'error');
291            // post to nc-wp-fail slack channel if payment status is equals to AUTHORISED or ERROR or REFUSED
292            if (in_array($paymentStatusName, array(Configure::read('worldpay.payment_status_authorised'), Configure::read('worldpay.payment_status_error'), Configure::read('worldpay.payment_status_refused')))) {
293                $this->slackWPErrorPostMsg($orderCode, '', $msg, $paymentStatusName);
294            }
295            // echo "[OK]"; exit;
296            return "[OK]"; 
297            // NJ-69126 I used return to force Stop Unit Test to process below and if use Exit it will stop the whole process also
298        }
299
300        if (!isset($paymentTransactionData['user_id'])) {
301            $msg = ' array key user_id does not exist.';
302            $this->log(__METHOD__ . ' ' . $msg . ' kickback data -->' . $dataJson, 'wp_debug');
303            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' kickback data -->' . $dataJson, 'error');
304            // post to nc-wp-fail slack channel if payment status is equals to AUTHORISED or ERROR or REFUSED
305            if (in_array($paymentStatusName, array(Configure::read('worldpay.payment_status_authorised'), Configure::read('worldpay.payment_status_error'), Configure::read('worldpay.payment_status_refused')))) {
306                $this->slackWPErrorPostMsg($orderCode, '', $msg, $paymentStatusName);
307            }
308            // echo "[OK]"; exit;
309            return "[OK]"; 
310            // NJ-69126 I used return to force Stop Unit Test to process below and if use Exit it will stop the whole process also
311        }
312
313        // set variables
314        $cardCompany = Configure::read('card_company.worldpay');
315        $typeId = 1; // default
316        $ptPaymentParams = json_decode($paymentTransactionData['payment_params'], true);
317        $logFileName = isset($ptPaymentParams['logFileName']) ? $ptPaymentParams['logFileName'] : 'debug';
318        $currencyCode = isset($ptPaymentParams['currencyCode']) ? $ptPaymentParams['currencyCode'] : null;
319        $formType = $ptPaymentParams['formType'];
320        $cronDateRun = isset($ptPaymentParams['cronDateRun']) ? $ptPaymentParams['cronDateRun'] : date('Y-m-d H:i:s');
321        $familyId = isset($ptPaymentParams['familyId']) ? $ptPaymentParams['familyId'] : null;
322        $userId = $familyId ? $familyId : $userId;
323        $receivablePayment = $liveLessonReceivable = $appreciationReceivable = 0;    
324
325        //remove user from currently paying users
326        UserTable::removePayingUserFromMemcache($userId);
327
328        if (!isset($ptPaymentParams['paymentAmount'])) {
329            $msg = 'Payment amount in payment transaction does not exist.';
330            $this->log(__METHOD__ . ' ' . $msg . ' kickback data -->' . $dataJson . ' - ' . json_encode($ptPaymentParams), $logFileName);
331            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' kickback data -->' . $dataJson . ' - ' . json_encode($ptPaymentParams), 'error');
332            $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
333            // echo "[OK]"; exit;
334            return "[OK]"; 
335            // NJ-69126 I used return to force Stop Unit Test to process below and if use Exit it will stop the whole process also
336        }
337
338        $amount = $ptPaymentParams['paymentAmount'];
339
340        // set user model
341        $uModel = $this->User;
342
343        // get user data
344        $userData = $uModel->find('first', array(
345            'fields' => array(
346                'status',
347                'nickname',
348                'email',
349                'hash',
350                'memo',
351                'parent_id',
352                'first_charge_date',
353                'next_charge_date',
354                'complimentary_code',
355                'payment_plan_id',
356                'monthly_speaking_attended_flg',
357                'monthly_speaking_business_attended_flg',
358                'id',
359                'hash16',
360                'currency_code',
361                'native_language2',
362                'charge_flg',
363                'fail_flg',
364                'double_check_flg',
365                'birthday',
366                'native_option',
367                'callan_option',
368                'aftee_transaction_identifier',
369                'card_token',
370                'card_company',
371                'platform',
372                'card_number',
373                'card_brand',
374                'wp_transaction_identifier'
375            ),
376            'conditions' => array('id' => $userId),
377            'recursive' => -1
378        ));
379
380        // return if user does not exist
381        if (!$userData) {
382            $this->log(__METHOD__ . ' User does not exist. payment transaction data --> ' . json_encode($paymentTransactionData) . ' | kickback data --> ' . $dataJson, $logFileName);
383            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - User does not exist. payment transaction data --> ' . json_encode($paymentTransactionData) . ' | kickback data --> ' . $dataJson, 'error');
384            // echo "[OK]"; exit;
385            return "[OK]"; 
386            // NJ-69126 I used return to force Stop Unit Test to process below and if use Exit it will stop the whole process also
387        }
388
389        // NC-9168: if card auth and user's currency does not match with processed payment currency, update to correct currency
390        if (!$userData['User']['currency_code']) {
391            if ($formType == Configure::read('payment_credit_authentication') && $currencyCode != $userData['User']['currency_code']) {
392                $uModel->validate = array();
393                $uModel->read(array('currency_code'), $userId);
394                $uModel->set(array('currency_code' => $currencyCode));
395                $uModel->save();
396                $this->log(__METHOD__ . ' Update to correct currency --> ' . $currencyCode . ' | userData -->' . json_encode($userData) . ' | kickback data --> ' . $dataJson, $logFileName);
397                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Update to correct currency --> ' . $currencyCode . ' | userData -->' . json_encode($userData) . ' | kickback data --> ' . $dataJson, 'error');
398            }
399            // NJ-69193 UNIT TETSING: Return early only during testing
400            if (getenv('UNIT_TESTING') === 'true') {
401                return;
402            }
403        }
404
405        // NC-5127: if family is withdrawn
406        if ($formType == Configure::read('payment_credit_family_monthly_payment') && $this->memcache->get('deactivated-user-'.$userId)) {
407            $this->log(__METHOD__ . ' User is withdrawn. ' . json_encode($data), 'monthly_payment');
408            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - User is withdrawn. ' . json_encode($data), 'error');
409            return ;
410        }
411
412        # NC-8194: check null payment_plan_id and price_id
413        if (
414            (!isset($ptPaymentParams['paymentPlanId']) || $ptPaymentParams['paymentPlanId'] == null) ||
415            (!isset($ptPaymentParams['priceId']) || $ptPaymentParams['priceId'] == null)
416        ) {
417            if ( $userData['User']['payment_plan_id'] && $userData['User']['price_id']) {
418                $paymentPlanId = $userData['User']['payment_plan_id'];
419                $priceId = $userData['User']['price_id'];
420            } else {
421                $defPlan = $this->PaymentPlanPrice->getDefaultPlan($userData['User']);
422                $paymentPlanId = $defPlan['paymentPlanId'];
423                $priceId = $defPlan['priceId'];
424            }
425
426            $ptPaymentParams['paymentPlanId'] = $paymentPlanId;
427            $ptPaymentParams['priceId'] = $priceId;
428
429            // NJ-69193 UNIT TETSING: Return early only during testing
430            if (getenv('UNIT_TESTING_01') === 'true') {
431                return;
432            }    
433        }
434
435        $nativeOptionPayment = 0;
436        $callanOptionPayment = 0;
437
438        // if monthly payment, retry or force charge
439        // check if user has receivable payment
440        if (in_array($formType, array(
441            Configure::read('payment_credit_monthly_payment'),
442            Configure::read('payment_credit_force_charge'),
443            Configure::read('payment_credit_retry'),
444            Configure::read('payment_credit_family_monthly_payment')
445        ))) {
446            // compute receivable payments
447            $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun);
448
449            // if has receivable payment
450            // deduct said monthly settlement from the money sent to zeus
451            if ($receivablePayment && $receivablePayment <= $amount) {
452                // deduct from monthly payment
453                $amount = $amount - $receivablePayment;
454            }
455
456            // if has native speaker payments
457            // deduct
458            if (isset($ptPaymentParams['nativeOptionPayment']) && $ptPaymentParams['nativeOptionPayment'] > 0) {
459                $nativeOptionPayment = $ptPaymentParams['nativeOptionPayment'];
460                $amount -= $nativeOptionPayment;
461            }
462
463            // if has callan option payments
464            // deduct
465            if (isset($ptPaymentParams['callanOptionPayment']) && $ptPaymentParams['callanOptionPayment'] > 0) {
466                $callanOptionPayment = $ptPaymentParams['callanOptionPayment'];
467                $amount -= $callanOptionPayment;
468            }
469
470            // compute appreciation receivable payments
471            $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.appreciation'));
472
473            // if has receivable payment
474            // deduct said monthly settlement from the money
475            if ($appreciationReceivable && $appreciationReceivable <= $amount) {
476                // deduct from monthly payment
477                $amount = $amount - $appreciationReceivable;
478            }
479
480            // compute live receivable payments
481            $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.live'));
482
483            // if has receivable payment
484            // deduct said monthly settlement from the money
485            if ($liveLessonReceivable && $liveLessonReceivable <= $amount) {
486                // deduct from monthly payment
487                $amount = $amount - $liveLessonReceivable;
488            }        
489            // NJ-69193 UNIT TETSING: Return early only during testing
490            if (getenv('UNIT_TESTING_02') === 'true') {
491                return;
492            }        
493
494        }
495
496        // Check receivables combine on `payment_credit_receivable` form type
497        if( $formType == Configure::read('payment_credit_receivable') ) {
498
499            // compute appreciation receivable payments
500            $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('appreciation_data.payment_element_type'));
501
502            // if has receivable payment
503            // deduct said monthly settlement from the money
504            if ($appreciationReceivable && $appreciationReceivable <= $amount) {
505                // deduct from monthly payment
506                $amount = $amount - $appreciationReceivable;
507            }
508
509            // compute live receivable payments
510            $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.live'));
511
512            if ($liveLessonReceivable && $liveLessonReceivable <= $amount) {
513                // deduct from monthly payment
514                $amount = $amount - $liveLessonReceivable;
515            }
516
517        }
518
519        // get receivables if form type payment credit change and amount is not equals to 0
520        if ($formType == Configure::read('payment_credit_change') && $amount > 0) {
521            // compute receivable payments
522            $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun);
523
524            // if has receivable payment
525            // deduct said monthly settlement from the money sent to zeus
526            if ($receivablePayment && $receivablePayment <= $amount) {
527                // deduct from monthly payment
528                $amount = $amount - $receivablePayment;
529            }
530
531            // compute appreciation receivable payments
532            $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.appreciation'));
533
534            // if has receivable payment
535            // deduct said monthly settlement from the money
536            if ($appreciationReceivable && $appreciationReceivable <= $amount) {
537                // deduct from monthly payment
538                $amount = $amount - $appreciationReceivable;
539            }
540
541            // compute live receivable payments
542            $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.live'));
543
544            if ($liveLessonReceivable && $liveLessonReceivable <= $amount) {
545                // deduct from monthly payment
546                $amount = $amount - $liveLessonReceivable;
547            }            
548        }
549
550        // save settlement history for tracking
551        $shData = array(
552            'userId' => $userId,
553            'params' => json_encode($data)
554        );
555
556        if (!SettlementHistoryTable::add($shData)) {
557            $msg = 'Saving user settlement history failed.';
558            $this->log(__METHOD__ . ' ' . $msg . ' data --> ' . json_encode($shData) . ' | kickback data --> ' . $dataJson, $logFileName);
559            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' data --> ' . json_encode($shData) . ' | kickback data --> ' . $dataJson, 'error');
560            $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
561            throw new InternalErrorException($msg);
562        }
563
564        $this->loadModel("ContinuationCampaign");
565        // prevent switching to replicas inside kickback
566        $this->Payment->setOverrideConnectFlg(true);
567        // if already have data stop/exit the process
568        $monthlyPaymentExist = $this->Payment->find('count', array(
569            'conditions' => array(
570                'Payment.user_id' => $userId,
571                'Payment.ordd' => $orderCode,
572                'Payment.card_company' => Configure::read('card_company.worldpay'),
573                'Payment.form_type' => $formType
574            )
575        ));
576        
577        if ($monthlyPaymentExist) {
578            $msg = ' Payments data already exist.';
579            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' --> ' . json_encode($data), 'error');
580            $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $data['PaymentStatus']);
581            // echo "[OK]"; exit;
582            return "[OK]";
583        }
584
585        switch($data['PaymentStatus']) {
586            case Configure::read('worldpay.payment_status_authorised'):
587
588                // NC-5543: return if payment method is debit and transaction identifier does not exist
589                if (!isset($data['transactionIdentifier']) && isset($data['PaymentMethod']) && in_array($data['PaymentMethod'], array('ECMC-SSL', 'MAESTRO-SSL', 'VISA-SSL'))) {
590                    $msg = 'Transaction identifier does not exist.';
591                    $this->log(__METHOD__ . ' ' . $msg . ' kickback data -->' . $dataJson, $logFileName);
592                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' kickback data -->' . $dataJson, 'error');
593                    $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
594                    // echo "[OK]"; exit;
595                    return "[OK]"; // ~ NJ-69193 I used "return" to force Stop Unit Test and to continue process below and if use Exit, it will stop the whole process also
596                }
597
598                $wpParams = array(
599                    'data' => $data,
600                    'ptData' => $paymentTransactionData,
601                    'logFileName' => $logFileName,                
602                    'amount' => $amount,
603                    'userData' => $userData,
604                    'cronDateRun' => $cronDateRun,
605                    'receivablePayment' => $receivablePayment,
606                    'appreciationReceivable' => $appreciationReceivable,
607                    'liveLessonReceivable' => $liveLessonReceivable,
608                    'transactionIdentifier' => isset($data['transactionIdentifier']) ? $data['transactionIdentifier'] : null
609                );
610
611                if( $formType == Configure::read('payment_credit_authentication') ) {
612
613                    //NJ-7548: fetch the user age $userData
614                    $uAge = UserTable::getStudentAge($userData['User']['birthday']);
615                    $uAge = $uAge ? (int) $uAge : null;
616                    $showAppreciationFlg = 0;
617
618                    //change the show appreciation flg if no birthday set or 18 and above            
619                    if (!$uAge || $uAge >= 18) {
620                        $showAppreciationFlg = 1;
621                    }
622
623                    // set user data
624                    $uModel->clear();
625                    $uModel->recursive = -1;
626                    $userSet = array( 'allow_appreciation_flg' => 1 , 'show_appreciation_flg' => $showAppreciationFlg);
627                    
628                    // set child card expiration date same as parent
629                    if (isset($ptPaymentParams['family_data']['applyPlan']['card_expiration_date'])) {
630                        $userSet['card_expiration_date'] = $ptPaymentParams['family_data']['applyPlan']['card_expiration_date'];
631                    }
632
633                    $uModel->read(array_keys($userSet), $userId);
634                    $uModel->set($userSet);
635                    $uModel->validate = array();
636                    if (!$uModel->save()) {
637                        $msg = 'Updating user failed.';
638                        $this->log(__METHOD__ . ' ' . $msg . ' data --> ' . json_encode($userSet) . ' | kickback data --> ' . $dataJson, $logFileName);
639                        $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' data --> ' . json_encode($userSet) . ' | kickback data --> ' . $dataJson, 'error');
640                        $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
641                        throw new InternalErrorException($msg);
642                    }
643
644                    if (isset($ptPaymentParams['userRegister']) && $ptPaymentParams['userRegister'] && $this->memcache->get('wp_register_completed_'.$userId)) {
645                        $msg = 'User already is enrolled Premium Plan(Free)';
646                        $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' data --> ' . json_encode($ptPaymentParams) . ' | mem data --> ' . $this->memcache->get('wp_register_completed_'.$userId) , 'error');
647                        $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
648                        return;
649                    }
650                }
651
652                // NJ-24425: release secured budget upon changing payment method FROM AFTEE to Worldpay
653                if ($formType == Configure::read('payment_credit_change')  
654                    && !empty($userData['User']['card_token']) && !empty($userData['User']['aftee_transaction_identifier'])
655                ) {
656                    // check if user is still Free (no monthly payment made yet)
657                    if ($userData['User']['payment_plan_id'] == Configure::read('payment_plans.free_trial')) {
658                        if (!class_exists('AfteePaymentService')) {
659                            App::uses('AfteePaymentService','Lib');
660                        }
661                        $afteeService = new AfteePaymentService();
662                        $checkRes = $afteeService->refund($userData, 'Change Payment Method');
663                        $this->log( '[NJ-24425] ' . json_encode($checkRes), 'aftee_debug');
664                        if ( !array_key_exists("object", $checkRes) || (isset($checkRes['object']) && $checkRes['object'] == 'error')) {
665                            $msg = '[Aftee] Failed to release secured budget';
666                            $this->log(__METHOD__ . ' ' . $msg . ' User data --> ' . json_encode($userData) . ' | refundData --> ' . json_encode($checkRes), 'aftee_debug');//AVOID [Warning] Array to string conversion
667                        }
668                    }
669                }
670                return $this->processWPPayment($wpParams);
671            case Configure::read('worldpay.payment_status_error'):
672            case Configure::read('worldpay.payment_status_refused'):
673                
674                $ptResponseText = json_decode($paymentTransactionData['response_text'], true);
675                $errorCode = isset($ptResponseText['directPayment_response']['paymentService']['reply']['orderStatus']['payment']['ISO8583ReturnCode']['@code']) ? $ptResponseText['directPayment_response']['paymentService']['reply']['orderStatus']['payment']['ISO8583ReturnCode']['@code'] : '';
676
677                // - delete token on error refused
678                if (
679                    isset($userData['User']['card_token']) &&
680                    !empty($userData['User']['card_token']) &&
681                    $errorCode == 54 // Expired Card
682                ) {
683                    $this->deleteUserToken(array(
684                        'deleteTokenParams' => array(
685                            'merchantCode' => isset($ptPaymentParams['merchantCode']) ? $ptPaymentParams['merchantCode'] : Configure::read('worldpay.merchant_code_usd'),
686                            'paymentTokenId' => $userData['User']['card_token'],
687                            'authenticatedShopperId' => $userId,
688                            'xmlName' => 'delete_token'
689                        ),
690                        'logFileName' => $logFileName,
691                        'dataJson' => $dataJson,
692                        'ptId' => $paymentTransactionData['id']
693                    ));
694
695                    // - removed user's saved card_token
696                    $uModel->clear();
697                    $uModel->recursive = -1;
698                    $uModel->read(['card_token'], $userId);
699                    $uModel->set(['card_token' => null]);
700                    $uModel->validate = array();
701                    $userSet = isset($userData) ? $userData : []; // FIX FOR Undefined variable $userSet
702                    if (!$uModel->save()) {
703                        $msg = 'Updating user card_token failed.';
704                        $this->log(__METHOD__ . ' ' . $msg . ' data --> ' . json_encode($userSet) . ' | kickback data --> ' . $dataJson, $logFileName);
705                        $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' data --> ' . json_encode($userSet) . ' | kickback data --> ' . $dataJson, 'error');
706                        $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
707                        throw new InternalErrorException($msg);
708                    }
709                }
710
711                switch ($formType) {
712                    case Configure::read('payment_credit_family_monthly_payment'):
713                    case Configure::read('payment_credit_monthly_payment'):
714                        // set user data
715                        $uModel->clear();
716                        $uModel->recursive = -1;
717                        $userSet = array(
718                            'fail_flg' => 1,
719                            'counseling_attended_flg' => 1,
720                            'charge_flg' => 0,
721                            'show_appreciation_flg' =>  0,
722                            'allow_appreciation_flg' => 0,
723                            'tip_max_amount' => null,
724                            'native_option' => 0,
725                            'callan_option' => 0,
726                            'next_charge_date' => null,
727                            'modified' => date('Y-m-d H:i:s')
728                        );
729
730                        if (isset($userData['User']['native_option']) && $userData['User']['native_option']) {
731                            $userSet['native_option_cancellation_time'] = date('Y-m-d H:i:s');
732                        }
733
734                        if (isset($userData['User']['callan_option']) && $userData['User']['callan_option']) {
735                            $userSet['callan_option_cancellation_time'] = date('Y-m-d H:i:s');
736                        }
737                        $uModel->read(array_keys($userSet), $userId);
738                        $memoStr = date('Y/m/d H:i:s')." Cancellation of Native Speaker Unlimited option";
739                        $memoStr2 = date('Y/m/d H:i:s')." Cancellation of Callan Unlimited option";
740                        $updatedMemo = $memoStr2."\n".$memoStr."\n".$userData['User']['memo'];
741                        $userSet['memo'] = $updatedMemo;
742
743                        $uModel->set($userSet);
744                        $uModel->validate = array();
745                        if (!$uModel->save()) {
746                            $msg = 'Updating user failed.';
747                            $this->log(__METHOD__ . ' ' . $msg . ' data --> ' . json_encode($userSet) . ' | kickback data --> ' . $dataJson, $logFileName);
748                            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' data --> ' . json_encode($userSet) . ' | kickback data --> ' . $dataJson, 'error');
749                            $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
750                            throw new InternalErrorException($msg);
751                        }
752
753                        $userTable = new UserTable($userData['User']);
754                        $membershipTypes = UserTable::getEngMembershipTypeData();
755                        $membershipTypeIndex = $userTable->getMembershipTypeIndex();
756                        $appreciationFlg = 0;
757                        $tipAmount = null;
758                        if (isset($ptPaymentParams['family_data']['applyPlan']['tip_max_amount']) && $ptPaymentParams['family_data']['applyPlan']['tip_max_amount']) {
759                            $tipAmount = $ptPaymentParams['family_data']['applyPlan']['tip_max_amount'];
760                        }
761                        if (isset($ptPaymentParams['family_data']['applyPlan']['allow_appreciation_flg']) && $ptPaymentParams['family_data']['applyPlan']['allow_appreciation_flg'] && $tipAmount) {
762                            $appreciationFlg = 1;
763                        }
764  
765                        $parentId = $userTable->parent_id;
766                        $is_cron = 0;
767                        if (php_sapi_name() == 'cli' || $ptPaymentParams['logFileName'] == 'monthly_payment'){
768                            $is_cron = 1;
769                        } 
770                        $currency_after = $userTable->currency_code;
771                        $plan_before = $ptPaymentParams['paymentPlanId'];
772                        $plan_after = $userTable->payment_plan_id;
773                        $usclData = array(
774                            'user_id' => $userId,
775                            'platform' => $userTable->platform ?? '',
776                            'card_company_before' => $userTable->card_company,
777                            'status_before' => $membershipTypes[$membershipTypeIndex],
778                            'status_after' => $membershipTypes[5],
779                            'controller_name' => 'payment',
780                            'action_name' => 'getWPPaymentResult',
781                            'parent_id' => $parentId,
782                            'is_cron' => $is_cron,
783                            'currency_before' => $ptPaymentParams['currencyCode'],
784                            'currency_after' => $currency_after,
785                            'payment_plan_id_before' => $plan_before,
786                            'payment_plan_id_after' => $plan_after,
787                            'default_appreciation_flg' => $appreciationFlg,
788                            'default_appreciation_amount' => $tipAmount
789                        );
790
791                        // save user change membership status
792                        if (!$this->UserStatusChangeLog->saveLog($usclData)) {
793                            $msg = 'Saving user status change log failed. - TOP';
794                            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' --> ' . json_encode($data), 'error');
795                            $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
796                            throw new InternalErrorException($msg);
797                        }
798
799                        //NJ-2814 add logs
800                        if (isset($ptPaymentParams['nativeOptionJoin']) && $ptPaymentParams['nativeOptionJoin']) {
801                            $nativeStatus = 1; // subscribed
802                            $statusBefore = $option_before_name = '';
803                        } else {
804                            $nativeStatus = 3; // unsubscribed
805                            $statusBefore = 1;
806                            $option_before_name = 'Native Unlimited Option';
807                        }
808
809                        $optionLogParams = array(
810                            'user_id' => $userId,
811                            'platform' => $ptPaymentParams['platform'],
812                            'status' => $nativeStatus,
813                            'controller_name' => $this->request->params['controller'],
814                            'action_name' => $this->request->params['action'],
815                            'user_type' => 0, // user
816                            'option_before' => $statusBefore,
817                            'option_after' => 1,
818                            'option_before_name' => $option_before_name,
819                            'option_after_name' => '',
820                            'option_type' => 1,
821                            'payment_plan_id' => $paymentPlanId
822                        );
823
824                        ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
825
826                        //NJ-2814 add logs
827                        if (isset($ptPaymentParams['callanOptionJoin']) && $ptPaymentParams['callanOptionJoin']) {
828                            $callanStatus = 1; // subscribed
829                            $statusBefore = $option_before_name = '';
830                        } else {
831                            $callanStatus = 3; // unsubscribed
832                            $statusBefore = 1;
833                            $option_before_name = 'Callan Unlimited Option';
834                        }
835
836                        $optionLogParams = array(
837                            'user_id' => $userId,
838                            'platform' => $ptPaymentParams['platform'],
839                            'status' => $callanStatus,
840                            'controller_name' => $this->request->params['controller'],
841                            'action_name' => $this->request->params['action'],
842                            'user_type' => 0, // user
843                            'option_before' => $statusBefore,
844                            'option_after' => 1,
845                            'option_before_name' => $option_before_name,
846                            'option_after_name' => '',
847                            'option_type' => 2,
848                            'payment_plan_id' => $paymentPlanId
849                        );
850
851                        ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
852
853                        // update user who join in ContinuationCampaign to fail status - 3
854                        if ($this->ContinuationCampaign->setFailedUser(array('user_id' => $userId))) {
855                            $msg = 'Failed to update ContinuationCampaign status to 3.';
856                            $this->log(__METHOD__ . ' ' . $msg . ' data --> ' . json_encode(array('user_id' => $userId)) . ' | kickback data --> ' . $dataJson, $logFileName);
857                            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' data --> ' . json_encode(array('user_id' => $userId)) . ' | kickback data --> ' . $dataJson, 'error');
858                            $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
859                            throw new InternalErrorException($msg);
860                        }
861                        
862                        // NJ-47740
863                        // confiscate pending request coupon for native and callan option
864                        $this->UsersCouponV1->confiscateOptionDiscount(array('userId' => $userId));
865
866                        // Get children list
867                        $childList = $uModel->getChildId($userId);
868
869                        // check if user is parent 
870                        if (!empty($childList)) {
871                            foreach ($childList as $childId) {
872                                // get child detail
873                                $familyMember = $uModel->find('first', array(
874                                    'fields' => array(
875                                        'User.id',
876                                        'User.memo',
877                                        'User.parent_id',
878                                        'User.native_option',
879                                        'User.callan_option'
880                                    ),
881                                    'conditions' => array('User.id' => $childId)
882                                ));
883                                $familyObj = new UserTable($familyMember['User']);
884                                $addMemo = 'Family plan[User]: family deactivation parent failed settlement';
885                                unset($familyObj->parent_id);
886
887                                // update children status to free
888                                if ($this->User->updateStatusToFree($familyObj, $addMemo)) {
889                                    // - deactivate reserved lessons of the children
890                                    $this->LessonSchedule->deactivateDisableReservedLessons($childId, true, false, true, null, false, true);
891
892                                    // NC-8645: add deactivation lock
893                                    UserTable::saveUserDeactivationLock($childId);
894
895                                    // NC-5342: add deactivation log
896                                    $this->loadModel('FamilyDeactivationLog');
897                                    $this->FamilyDeactivationLog->addLog($childId);
898                                }
899
900                                $switchAccountParams = array(
901                                    'parentId' => $userId,
902                                    'userId' => $childId
903                                );
904                                
905                                // NJ-47740
906                                // confiscate pending request coupon for native and callan option
907                                $this->UsersCouponV1->confiscateOptionDiscount(array('userId' => $childId));
908                                
909                                // delete switch account data
910                                $this->UsersFamilyAccount->removeSwitchAccount($switchAccountParams);
911                            }
912                        }
913
914                        if ($nativeOptionPayment > 0) {
915                            $nativeOptionDiscount = isset($ptPaymentParams['nativeOptionDiscount']) && $ptPaymentParams['nativeOptionDiscount'] ? $ptPaymentParams['nativeOptionDiscount'] : 0;
916                            $paymentNOData = array(
917                                'user_id' => $userId,
918                                'type_id' => $typeId,
919                                'pay_kbn' => 1,
920                                'form_type' => Configure::read('payment_native_option_monthly_payment'),
921                                'reference_id' => $userId,
922                                'amount' => $nativeOptionPayment,
923                                'ordd' => $orderCode,
924                                'card_company' => $cardCompany,
925                                'param1' => $dataJson,
926                                'param2' => 'error: wp',
927                                'transaction_code' => $orderCode,
928                                'currency_code' => $currencyCode,
929                                'payment_plan_id' => isset($ptPaymentParams['paymentPlanId']) ? $ptPaymentParams['paymentPlanId'] : null,
930                                'price_id' => isset($ptPaymentParams['priceId']) ? $ptPaymentParams['priceId'] : null,
931                                'payment_type' => isset($ptPaymentParams['paymentType']) ? $ptPaymentParams['paymentType'] : null,
932                                'discounted_amount' => $nativeOptionDiscount
933                            );
934
935                            // set payment model
936                            $pModel = $this->Payment;
937                            $pModel->clear();
938                            $pModel->create();
939                            $pModel->recursive = -1;
940                            $pModel->set($paymentNOData);
941                            $pModel->validate = array();
942
943                            if (!$pSave = $pModel->save()) {
944                                $msg = 'Saving payment failed.';
945                                $this->log(__METHOD__ . ' ' . $msg . ' data --> ' . json_encode($paymentNOData) . ' | kickback data --> ' . $dataJson, $logFileName);
946                                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' data --> ' . json_encode($paymentNOData) . ' | kickback data --> ' . $dataJson, 'error');
947                                $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
948                                throw new InternalErrorException($msg);
949                            }
950                        }
951
952                        if ($callanOptionPayment > 0) {
953                            $callanOptionDiscount = isset($ptPaymentParams['callanOptionDiscount']) && $ptPaymentParams['callanOptionDiscount'] ? $ptPaymentParams['callanOptionDiscount'] : 0;
954                            $paymentNOData = array(
955                                'user_id' => $userId,
956                                'type_id' => $typeId,
957                                'pay_kbn' => 1,
958                                'form_type' => Configure::read('payment_callan_option_monthly_payment'),
959                                'reference_id' => $userId,
960                                'amount' => $callanOptionPayment,
961                                'ordd' => $orderCode,
962                                'card_company' => $cardCompany,
963                                'param1' => $dataJson,
964                                'param2' => 'error: wp',
965                                'transaction_code' => $orderCode,
966                                'currency_code' => $currencyCode,
967                                'payment_plan_id' => isset($ptPaymentParams['paymentPlanId']) ? $ptPaymentParams['paymentPlanId'] : null,
968                                'price_id' => isset($ptPaymentParams['priceId']) ? $ptPaymentParams['priceId'] : null,
969                                'payment_type' => isset($ptPaymentParams['paymentType']) ? $ptPaymentParams['paymentType'] : null,
970                                'discounted_amount' => $callanOptionDiscount
971                            );
972
973                            // set payment model
974                            $pModel = $this->Payment;
975                            $pModel->clear();
976                            $pModel->create();
977                            $pModel->recursive = -1;
978                            $pModel->set($paymentNOData);
979                            $pModel->validate = array();
980
981                            if (!$pSave = $pModel->save()) {
982                                $msg = 'Saving payment failed.';
983                                $this->log(__METHOD__ . ' ' . $msg . ' data --> ' . json_encode($paymentNOData) . ' | kickback data --> ' . $dataJson, $logFileName);
984                                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' data --> ' . json_encode($paymentNOData) . ' | kickback data --> ' . $dataJson, 'error');
985                                $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
986                                throw new InternalErrorException($msg);
987                            }
988                        }
989                    case Configure::read('payment_credit_receivable'):
990                    case Configure::read('payment_credit_retry'):
991                    case Configure::read('payment_credit_force_charge'):
992                        // - save refuse payments
993                        $ptPaymentParams["paymentAmount"] = $amount;
994                        $data["user_id"] = $userId;
995                         $data["formType"] = $formType;
996                        if(!$this->worldpay_error_log_set($data, $ptPaymentParams)){
997                            $this->log(__METHOD__ . ' world_pay error saving payment', 'debug');
998                            $this->log(__METHOD__ . ' world_pay error saving payment', 'wp_debug');
999                            return;
1000                        }
1001                        
1002                    case Configure::read('payment_credit_authentication'):
1003                    case Configure::read('payment_credit_change'):
1004                        $ptUpdate = $this->updatePaymentTransaction(array(
1005                            'id' => $paymentTransactionData['id'],
1006                            'fields' => array(
1007                                'status' => 2, // error
1008                                'payment_id' => isset($pSave['Payment']['id']) ? $pSave['Payment']['id'] : null,
1009                                'response_text' => array('wp_kickback' => json_decode($dataJson, true))
1010                            ),
1011                            'logFileName' => $logFileName
1012                        ));
1013
1014                        if (!$ptUpdate) {
1015                            $msg = 'Updating payment transaction failed.';
1016                            $this->log(__METHOD__ . ' ' . $msg . ' data --> ' . json_encode(array('pt_id' => $paymentTransactionData['id'])) . ' | kickback data --> ' . $dataJson, $logFileName);
1017                            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' data --> ' . json_encode(array('pt_id' => $paymentTransactionData['id'])) . ' | kickback data --> ' . $dataJson, 'error');
1018                            $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
1019                            throw new InternalErrorException($msg);
1020                        }
1021                        break;
1022                }
1023                break;
1024            default:
1025                $this->log(__METHOD__ . ' No data save', $logFileName);
1026                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - No data save', 'error');
1027                break;
1028        }
1029        // echo "[OK]"; exit;
1030        return "[OK]"; // ~ NJ-69193 I used "return" to force Stop Unit Test and to continue process below and if use Exit, it will stop the whole process also
1031    }
1032
1033    //NJ-69193 ! UNIT TEST purposes private to public
1034    public function worldpay_error_log_set($data = array(), $paymentParams = array()) {
1035
1036        // set the variables
1037        $userId = isset($data['user_id']) ? $data['user_id'] : 0;
1038        $money = isset($paymentParams['paymentAmount']) ? $paymentParams['paymentAmount'] : 0;
1039        $cardCompany = Configure::read('card_company.worldpay');
1040        $formType = isset($data['formType']) ? $data['formType'] : 0;
1041        $orderCode = isset($data['OrderCode']) ? $data['OrderCode'] : null;
1042        $paymentStatusName = isset($data['PaymentStatus']) ? $data['PaymentStatus'] : '';
1043        $logFileName = isset($ptPaymentParams['logFileName']) ? $ptPaymentParams['logFileName'] : 'debug';
1044        $result = array();
1045
1046        $paymentType = isset($paymentParams['paymentType']) ? $paymentParams['paymentType'] : null;
1047        $priceId = isset($paymentParams['priceId']) ? $paymentParams['priceId'] : null;
1048        $paymentId = isset($paymentParams['paymentPlanId']) ? $paymentParams['paymentPlanId'] : null;
1049        $currencyCode = isset($paymentParams['currencyCode']) ? $paymentParams['currencyCode'] : Configure::read('currency_jpy');
1050        // $discounted_amount = isset($paymentParams['discounted_amount']) ? $paymentParams['discounted_amount'] : 0;
1051
1052        // check if has monthly discount
1053        $discounted_amount = isset($paymentParams['monthlyDiscount']) && $paymentParams['monthlyDiscount'] ? $paymentParams['monthlyDiscount'] : 0;
1054        if (!empty($paymentParams['couponUseSettlement']) && !empty($paymentParams['couponUseSettlement']['useCouponAmount']) && in_array($formType, Configure::read('allow_coupon.settlement_form_type'))) {
1055            $discounted_amount += (int)$paymentParams['couponUseSettlement']['useCouponAmount'];
1056        }
1057
1058        // Check receivable type
1059        $cronDateRun = date("Y-m-d H:i:s");
1060        $receivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun);
1061        $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('appreciation_data.payment_element_type'));
1062        $liveReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.live'));
1063
1064        try {
1065            $paymentData = array(
1066                'user_id' => $userId,
1067                'type_id' => 1,
1068                'pay_kbn' => 1,
1069                'form_type' => $formType,
1070                'reference_id' => $userId,
1071                'amount' => $money,
1072                'ordd' => $orderCode,
1073                'card_company' => $cardCompany,
1074                'param1' => json_encode($data),
1075                'param2' => 'error: wp',
1076                'transaction_code' => $orderCode,
1077                'currency_code' => $currencyCode,
1078                'payment_plan_id' => $paymentId,
1079                'price_id' => $priceId,
1080                'payment_type' => $paymentType,
1081                'discounted_amount' => $discounted_amount
1082            );
1083
1084            // set payment model
1085            $pModel = $this->Payment;
1086            $pModel->clear();
1087            $pModel->create();
1088            $pModel->recursive = -1;
1089            $pModel->set($paymentData);
1090            $pModel->validate = array();
1091            $result[$formType][] = $pModel->save();
1092
1093        } catch (\Throwable $th) {
1094            $dataJson = json_encode($data);
1095            $msg = 'Saving payment failed.';
1096            $this->log(__METHOD__ . ' ' . $msg . ' data --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, $logFileName);
1097            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' data --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, 'error');
1098            $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
1099        }
1100
1101        if (
1102            in_array($formType, array(
1103                Configure::read('payment_credit_appreciation_receivable'),
1104                Configure::read('payment_credit_receivable'),
1105                Configure::read('payment_credit_monthly_payment'),
1106                Configure::read('payment_credit_force_charge'),
1107                Configure::read('payment_credit_retry'),
1108                Configure::read('payment_credit_family_monthly_payment')
1109            )) ||
1110            (
1111                $formType == Configure::read('payment_credit_change') &&
1112                (
1113                    $receivable ||
1114                    $appreciationReceivable ||
1115                    $liveReceivable
1116                )
1117            )
1118        ) {
1119            // Appreciation 
1120            if( $appreciationReceivable > 0 ) {
1121                $this->Payment->clear();
1122                $this->Payment->create();
1123                $this->Payment->set(array(
1124                    'user_id' => $userId,
1125                    'type_id' => 1,
1126                    'pay_kbn' => 1,
1127                    'form_type' => Configure::read('payment_credit_appreciation_receivable'),
1128                    'reference_id' => $userId,
1129                    'amount' => $appreciationReceivable,
1130                    'ordd' => $orderCode,
1131                    'card_company' => $cardCompany,
1132                    'param1' => json_encode($data),
1133                    'param2' => "error: wp",
1134                    'transaction_code' => $orderCode,
1135                    'currency_code' => $currencyCode,
1136                    'price_id' => $priceId,
1137                    'payment_id' => $paymentId,
1138                    'payment_type' => $paymentType,
1139                    'discounted_amount' => $discounted_amount
1140                ));
1141                $resApp = $this->Payment->save();
1142                if (!$resApp) {
1143                    CakeLog::debug(__METHOD__ . 'Error : saving appreciation receivable -> params' . json_encode([$data, $paymentParams]));
1144                }
1145                $result[$formType][] = $resApp;
1146            }
1147
1148            // Live receivable 
1149            if( $liveReceivable > 0 ) {
1150                $this->Payment->clear();
1151                $this->Payment->create();
1152                $this->Payment->set(array(
1153                    'user_id' => $userId,
1154                    'type_id' => 1,
1155                    'pay_kbn' => 1,
1156                    'form_type' => Configure::read('payment_live_lesson_receivable'),
1157                    'reference_id' => $userId,
1158                    'amount' => $liveReceivable,
1159                    'ordd' => $orderCode,
1160                    'card_company' => $cardCompany,
1161                    'param1' => json_encode($data),
1162                    'param2' => "error: wp",
1163                    'transaction_code' => $orderCode,
1164                    'currency_code' => $currencyCode,
1165                    'price_id' => $priceId,
1166                    'payment_id' => $paymentId,
1167                    'payment_type' => $paymentType,
1168                    'discounted_amount' => $discounted_amount
1169                ));
1170                $resLive = $this->Payment->save();
1171                if (!$resLive) {
1172                    CakeLog::debug(__METHOD__ . 'Error : saving live receivable -> params' . json_encode([$data, $paymentParams]));
1173                }
1174                $result[$formType][] = $resLive;
1175            }        
1176
1177            // Reservation
1178            if( $receivable > 0 ) {
1179                $this->Payment->clear();
1180                $this->Payment->create();
1181                $this->Payment->set(array(
1182                    'user_id' => $userId,
1183                    'type_id' => 1,
1184                    'pay_kbn' => 1,
1185                    'form_type' => Configure::read('payment_credit_receivable'),
1186                    'reference_id' => $userId,
1187                    'amount' => $receivable,
1188                    'ordd' => $orderCode,
1189                    'card_company' => $cardCompany,
1190                    'param1' => json_encode($data),
1191                    'param2' => "error: wp",
1192                    'transaction_code' => $orderCode,
1193                    'currency_code' => $currencyCode,
1194                    'price_id' => $priceId,
1195                    'payment_id' => $paymentId,
1196                    'payment_type' => $paymentType,
1197                    'discounted_amount' => $discounted_amount
1198                ));
1199                $resReservation = $this->Payment->save();
1200                if (!$resReservation) {
1201                    CakeLog::debug(__METHOD__ . 'Error : saving reservation receivable -> params' . json_encode([$data, $paymentParams]));
1202                }
1203                $result[$formType][] = $resReservation;
1204            }
1205        }
1206
1207        return $result;
1208    }
1209
1210    public function complete() {
1211        $UsersCoursesData = $this->UsersCourses->findByUserId($this->Auth->user('id'));
1212        $usersCourses = isset($UsersCoursesData['UsersCourses']) ? $UsersCoursesData['UsersCourses'] : null;
1213        $courseMasterData = $this->CourseMaster->findById($usersCourses['course_id']);
1214        $courseMaster = isset($courseMasterData['CourseMaster']) ? $courseMasterData['CourseMaster'] : null;
1215        $UsersPointsData = $this->UsersPoints->findByUserId($this->Auth->user('id'));
1216        $usersPoints = isset($UsersPointsData['UsersPoints']) ? $UsersPointsData['UsersPoints'] : null;
1217        $courseMasterTable = new CourseMasterTable($courseMaster);
1218        $this->set(array(
1219            'courseMasterTable' => $courseMasterTable,
1220            'purchasePoints' => $courseMaster['add_point'],
1221            'totalPoints' => $usersPoints['point'],
1222            'purchasePointsPrice' => $courseMaster['price']
1223        ));
1224    }
1225    /**
1226     * @api {get} /payment/points/complete pointsComplete()
1227     * @apiName pointsComplete
1228     * @apiGroup Payment
1229     * @apiDescription This endpoint is used to display the points compelete page.
1230     * 
1231     * @apiSuccess {View} Render Renders the points complete page.
1232     * 
1233     * @apiError {View} Redirects back to {{ENV}}/home if the payment data is not found.
1234     * 
1235     * @apiSuccessExample Success Response:
1236     * Renders the points complete page.
1237     * 
1238     * @apiErrorExample Error Response:
1239     * Redirects back to {{ENV}}/home if the payment data is not found.
1240     * 
1241     * @apiSampleRequest off
1242     */
1243    public function pointsComplete() {
1244        $UsersPointsData = $this->UsersPoints->findByUserId($this->Auth->user('id'));
1245        $conditions = array(
1246            'user_id' => $this->Auth->user('id')
1247        );
1248        $paymentData = $this->Payment->find('first',array(
1249            'conditions' => $conditions,
1250            'order' => 'Payment.created DESC'
1251        ));
1252        if (!$paymentData) {
1253            return $this->redirect(myTools::getUrl() . '/home');
1254        }
1255
1256        $payment = $paymentData['Payment'];
1257        $usersPoints = $UsersPointsData['UsersPoints'];
1258        $courseMaster = $paymentData['CourseMaster'];
1259
1260        $this->set(array(
1261            'purchasePoints' => $courseMaster['add_point'],
1262            'totalPoints' => $usersPoints['point'],
1263            'price' => $payment['amount']
1264        ));
1265    }
1266
1267    public function callback() {
1268        $this->autoRender = false;
1269        $this->savePdataLog(2);
1270    }
1271
1272    protected function checkCallBack() {
1273        $data = $this->data;
1274
1275        if (!$this->data) {
1276            return $this->redirect(myTools::getUrl() . '/home');
1277        }
1278        if ($data['custom'] != $this->Auth->user('id')) {
1279            // die('User not authorize!');
1280            return "User not authorize!";
1281        }
1282        $courseMasterData = $this->CourseMaster->findById($data['item_number1']);
1283        if (!isset($courseMasterData)) {
1284            // die('Invalid Course ID');
1285            return "Invalid Course ID";
1286        }
1287        $courseMaster = $courseMasterData['CourseMaster'];
1288        if ($courseMaster['price'] > $data['mc_gross']) {
1289            // die('Invalid amount');
1290            return "Invalid amount";
1291        }
1292        if ($data['payment_status'] != 'Completed') {
1293            // die('Payment not yet completed');
1294            return 'Payment not yet completed';
1295        }
1296        return $data;
1297    }
1298
1299    /*
1300    1 = return transfer data
1301    2 = IPN or Instant payment notification
1302    */
1303    protected function savePdataLog() {
1304        if ($_REQUEST) {
1305            $data = $_REQUEST;
1306            $data['referer'] = $_SERVER['HTTP_REFERER'];
1307            $data['ip'] = $_SERVER['REMOTE_ADDR'];
1308            $this->data = $data;
1309        }
1310    }
1311
1312
1313
1314    /**
1315     * 以下 テレコム決済周り
1316     **/
1317
1318    public function t_start() {
1319
1320        $userData = $this->User->findById($this->Auth->user('id'));
1321        if (!$userData) {
1322            return $this->redirect(myTools::getUrl() . '/');
1323        }
1324        $user = new UserTable($userData['User']);
1325
1326
1327        // 既に有料会員の場合
1328        if ($user->charge_flg) {
1329            return $this->redirect(myTools::getUrl() . '/');
1330        }
1331
1332        // 既に登録済みの場合(念のため)
1333        $data = $this->PaymentTransaction->findByPaymentHashAndStatusAndUserId($this->Auth->user('hash16'), 1, $this->Auth->user('id'));
1334        if ($data) {
1335            return $this->redirect(myTools::getUrl() . '/');
1336        }
1337
1338        // テレコム遷移用データ
1339        App::uses('telecomcheckout','Vendor');
1340        $telecom = new telecomcheckout();
1341
1342        // 固定
1343        $courseId = Configure::read("credit.course_id");
1344
1345        // set the default password
1346        $password = myTools::generateRandomStr(8);
1347
1348        // set course param
1349        $course = new stdClass();
1350
1351
1352        // create payment transaction
1353        $this->PaymentTransaction->create();
1354        $this->PaymentTransaction->set(array(
1355            'user_id' => $this->Auth->user('id'),
1356            'payment_hash' => $user->hash16,
1357            'status' => 0,
1358            'course_id' => $courseId,
1359            'password' => $password,
1360        ));
1361        $this->PaymentTransaction->save();
1362
1363
1364        // 事前登録会員と通常会員でIDを分ける
1365        #$course->rebill_param_id = ($user->member_kbn==1) ? '1month3900yen_2' : '1month3900yen';
1366
1367#        $course->rebill_param_id = '1month3900yen_3';
1368
1369        // NC-213で更新
1370#        $course->rebill_param_id = '1month3900yen';
1371
1372        // NC-416で更新
1373        $course->rebill_param_id = Configure::read("credit.rebill_param_id");
1374
1375        // set to telecom parameters
1376        $telecom->setParams(array(
1377            'sendid'            => $user->hash16,
1378            'usrmail'           => $user->email,
1379            'redirect_url'      => '',
1380            'redirect_back_url' => '',
1381            'rebill_param_id'   => $course->rebill_param_id,
1382            'option'            => $courseId,
1383            'sendpass'          => $password,
1384        ));
1385        // fetch telecom parameters
1386        $params = $telecom->getParams();
1387        $url = $telecom->auth_url . '?';
1388        foreach ($params as $key => $val) {
1389            $url .= $key . '=' . $val . '&';
1390        }
1391        return $this->redirect($url);
1392    }
1393
1394    public function charge_company_select(){
1395
1396    }
1397
1398    /**
1399     * @api {post} /payment/z_start/:data/:formType/:referrer z_start()
1400     * @apiName z_start
1401     * @apiGroup Payment
1402     * @apiDescription This endpoint is used to start the payment process in zeus.
1403     * 
1404     * @apiParam {Object} data The payment data.
1405     * @apiParam {String} [data.ZPaymentFullLogs.clientip] The client's IP address.
1406     * @apiParam {Number} [data.ZPaymentFullLogs.cardnumber] The card number.
1407     * @apiParam {Number} [data.ZPaymentFullLogs.expyy] The card's expiration year.
1408     * @apiParam {Number} [data.ZPaymentFullLogs.expmm] The card's expiration month.
1409     * @apiParam {Number} [data.ZPaymentFullLogs.telno] The telephone number.
1410     * @apiParam {String} [data.ZPaymentFullLogs.username] The username.
1411      * @apiParam {String} [data.ZPaymentFullLogs.paymentHash] The payment hash.
1412     * @apiParam {Number} [data.ZPaymentFullLogs.discounted_amount] The discounted amount.
1413     * @apiParam {String} [data.ZPaymentFullLogs.zeusTokenValue] The Zeus token value.
1414     * @apiParam {String} [data.zeus_card_option] The Zeus card option.
1415     * @apiParam {String} [data.origin_redirect] The origin redirect URL.
1416     * @apiParam {String} formType The form type.
1417     * @apiParam {String} referrer The referrer url.
1418     * 
1419     * @apiSuccess (View) Redirect /payment/payment_credit_register_complete Redirects to payment credit register complete.
1420     * @apiSuccess (View) Redirect /payment/payment_credit_charge_complete Redirects to payment credit charge complete.
1421     * @apiSuccess (View) Redirect /payment/coupon_payment_credit_charge_complete Redirects to coupon payment credit charge complete.
1422      * @apiSuccess (View) Redirect /payment/payment_credit_change_complete Redirects to payment credit change complete.
1423     * @apiSuccess (View) Redirect /store/card_register_complete Redirects to card register complete.
1424     * @apiSuccess (View) Redirect /payment/payment_credit_retry_complete Redirects to payment credit retry complete.
1425     * @apiSuccess (View) Redirect /StudyAbroad/payment_complete Redirects to study abroad payment complete.
1426     * 
1427     * @apiError (View) Redirect / Redirects to home page.
1428     * 
1429     * @apiSuccessExample Success Response payment credit authentication:
1430     * Redirects to {{ENV}}//payment/payment_credit_register_complete
1431     * 
1432     * @apiSUccessExample Success Response payment_credit_force_charge:
1433     * Redirects to {{ENV}}/payment/payment_credit_charge_complete
1434     * 
1435     * @apiSuccessExample Success Response payment_credit_force_charge with complimentary user:
1436     * Redirects to {{ENV}}/payment/coupon_payment_credit_charge_complete
1437     * 
1438     * @apiSuccessExample Success Response payment_credit_change:
1439     * Redirects to {{ENV}}/payment/payment_credit_change_complete
1440     * 
1441     * @apiSuccessExample Success Response payment_credit_change & origin is store:
1442     * Redirects to {{ENV}}/store/card_register_complete
1443     * 
1444     * @apiSuccessExample Success Response payment_credit_retry:
1445     * Redirects to {{ENV}}/payment/payment_credit_retry_complete
1446     * 
1447     * @apiSuccessExample Success Response payment_study_abroad:
1448     * Redirects to {{ENV}}/StudyAbroad/payment_complete
1449     * 
1450     * @apiErrorExample Error Response:
1451     * Redirects to {{ENV}}/
1452     * 
1453     * @apiSampleRequest off
1454     */
1455    public function z_start($data = null, $formType = null, $referrer = null){
1456        $this->autoRender = false;
1457        if (!$userData = $this->sharedUserData['User']) {
1458            return $this->redirect(myTools::getUrl() . '/');
1459        }
1460        $user = new UserTable($this->sharedUserData['User']); //NJ-69193 ~ Fix the error in $user below
1461        $modelname ="ZPaymentFullLogs";
1462        $this->set(compact("modelname"));
1463
1464        if ($data) {
1465            switch ($formType) {
1466                case Configure::read('payment_credit_retry'):
1467                    // NJ-47740 - get monthly reqeust coupon discount
1468                    $coupon = $this->UsersCouponV1->getCouponUseRequest(array(
1469                        'userId' => $userData['id'],
1470                        'kbn' => Configure::read('coupon_kbn.monthly_settlement')
1471                    ));
1472
1473                    if (!empty($coupon['amount']) && !empty($coupon['grp_id'])) {
1474                        $discountedCoupon = $coupon['amount'];
1475                        
1476                        if ($discountedCoupon >= $data[$modelname]['money']) {
1477                            $data[$modelname]['discounted_amount'] = $data[$modelname]['money'];
1478                            $data[$modelname]['money'] = 0;
1479                        } else {
1480                            $discountedAmount = $discountedCoupon ? $discountedCoupon : 0;
1481                            $data[$modelname]['money'] -= $discountedAmount;
1482                        }
1483                    }
1484                case Configure::read('payment_credit_force_charge'):
1485                case Configure::read('payment_individual_corporate_standard'):
1486                case Configure::read('payment_individual_corporate_premium'):
1487                case Configure::read('payment_lite_credit_paid'):
1488                case Configure::read('payment_credit_change'):
1489                case Configure::read('payment_credit_chocotto_monthly_payment'):
1490                case Configure::read('payment_credit_chocotto_force_charge'):
1491                    $annualDiscountOptionData = [];
1492                    $annualDiscountOptionAmount = 0;
1493                    if ($formType == Configure::read('payment_credit_retry')) {
1494                        // get user active annual discount option
1495                        $annualDiscountOptionData = $this->UserDiscountOptionsTerm->getTerm([
1496                            'user_id' => $userData['id'],
1497                            'discount_option_id' => Configure::read('discount_option.annual.plan_id'),
1498                            'status' => 1
1499                        ]);
1500                    } elseif ($formType == Configure::read('payment_credit_force_charge')) {
1501                        $annualDiscountOptionData = $this->DiscountOptionsPrice->getPaymentData([
1502                            'currencyCode' => $userData['currency_code'],
1503                            'discountOptionId' => Configure::read('discount_option.annual.plan_id')
1504                        ]);
1505                    }
1506
1507                    if ($annualDiscountOptionData) {
1508                        $annualDiscountOptionAmount = $annualDiscountOptionData['amount'];
1509                    }
1510
1511                    // - check if not annual discount option
1512                    if(isset($data[$modelname]['payment_plan_type']) && $data[$modelname]['payment_plan_type'] == 0) {
1513                        $annualDiscountOptionAmount = 0;
1514                    }
1515
1516                    // get reserve payment receivable
1517                    $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userData['id']);
1518
1519                    // get appreciation payment receivable
1520                    $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userData['id'], false, Configure::read('appreciation_data.payment_element_type'));
1521
1522                    // get live lesson payment receivable
1523                    $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userData['id'], false, Configure::read('payment_element_type.live'));
1524
1525                    $money = $data[$modelname]['money'] + $receivablePayment + $appreciationReceivable + $liveLessonReceivable;
1526                    $money -= $annualDiscountOptionAmount;
1527
1528                    break;
1529                case Configure::read('payment_prepaid_corporate_light_member'):
1530                case Configure::read('payment_study_abroad'):
1531                    $money = $data[$modelname]['money'];
1532                    break;
1533                case Configure::read('payment_credit_authentication'):
1534                case Configure::read('payment_lite_credit_free'):
1535                case Configure::read('payment_credit_chocotto_free'):                
1536                    $money = 0;
1537                    break;
1538                default:
1539                    $money = 0;
1540                    $formType = Configure::read('payment_credit_default');
1541                    break;
1542            }
1543
1544            $pData = array(
1545                'clientIp' => (int) $data[$modelname]['clientip'],
1546                'cardNumber' => $data[$modelname]['cardnumber'],
1547                'expyy' => isset($data[$modelname]['expyy']) ? (int) $data[$modelname]['expyy'] : 0,
1548                'expmm' => isset($data[$modelname]['expmm']) ? (int) $data[$modelname]['expmm'] : 0,
1549                'telNo' => (int) $data[$modelname]['telno'],
1550                'email' => $userData['email'],
1551                'username' => $data[$modelname]['username'],
1552                'sendId' => (int) $userData['id'],
1553                'money' => $money,
1554                'tokenKey' => isset($data[$modelname]['zeusTokenValue']) ? $data[$modelname]['zeusTokenValue'] : null,
1555                'paymentHash' => $data[$modelname]['paymentHash']
1556            );
1557
1558            // send curl request
1559            if (isset($data['zeus_card_option']) && $data['zeus_card_option'] == "prev") {
1560                $res = ZChargeComponent::charge_with_regsterd_card(json_encode($pData));
1561            } else {
1562
1563                // update payment params -  add card expiration date
1564                if (isset($data[$modelname]['expyy']) && isset($data[$modelname]['expmm'])) {
1565                    $paymentParamsData = array('cardExpirationDate' => date('Y-m-t', strtotime($data[$modelname]['expyy'] . '-' . $data[$modelname]['expmm'])));
1566                    $this->PaymentTransaction->updatePaymentParams(array('paymentHash' => $data[$modelname]['paymentHash'], 'updateData' => $paymentParamsData));
1567                }
1568
1569                // get zeus challenge flag
1570                $zeus3DSecureChallengeFlg = $this->memcache->get('zeus3DSecureChallengeFlg_' . $userData['id']);
1571                
1572                // NJ-25522: payment was charged after challenge already
1573                if ($zeus3DSecureChallengeFlg) {
1574                    $zeus3DSecurePaymentSuccessFlg = $this->memcache->get('zeus3DSecurePaymentSuccessFlg_' . $userData['id']);
1575                    $res = !empty($zeus3DSecurePaymentSuccessFlg) && $zeus3DSecurePaymentSuccessFlg == 'OK' ? 'Success_order' : 'failure_order';
1576
1577                    // clear flag
1578                    $this->memcache->delete('zeus3DSecureChallengeFlg_' . $userData['id']);
1579                    $this->memcache->delete('zeus3DSecurePaymentSuccessFlg_' . $userData['id']);
1580
1581                // default process without challenge, charge directly
1582                } else {
1583                    $res = $this->ZCharge->charge_regist(json_encode($pData));
1584
1585                }
1586            }
1587
1588            // if successful
1589            if (isset($res) && ($res[0] == "Success_order" || $res == "Success_order")) {
1590                $re_campaign = $this->UserWithdrawReenrollCampaign->find('first', array(
1591                    'conditions' => array(
1592                        'user_id' => $this->Auth->user("id")
1593                    ),
1594                    'fields' => array('id', 'status')
1595                ));
1596                if (
1597                    isset($re_campaign['UserWithdrawReenrollCampaign']['status']) && 
1598                    $re_campaign['UserWithdrawReenrollCampaign']['status'] == 0 &&
1599                    $user->currency_code == Configure::read('currency_jpy')
1600                ) {
1601                    // give 500 points
1602                    $pointParams = array(
1603                        'userId' => $user->id,
1604                        'point' => 500, // re-register campaign points
1605                        'kbn' => Configure::read("point_history.bonus"),
1606                        'kbnType' => 1, // add coin
1607                        'coinType' => 2, // service coin
1608                        'coinFailMessage' => Configure::read('coin.failed.buy_coin')
1609                    );
1610                    ClassRegistry::init('UsersPoint')->performPointTransaction($pointParams);
1611
1612                    // update re-enroll campaign status
1613                    $update_reenroll_campaign = array(
1614                        'id' => $re_campaign['UserWithdrawReenrollCampaign']['id'],
1615                        'status' => 1,
1616                    );
1617                    $this->UserWithdrawReenrollCampaign->clear();
1618                    $this->UserWithdrawReenrollCampaign->read(array_keys($update_reenroll_campaign),$update_reenroll_campaign['id']);
1619                    $this->UserWithdrawReenrollCampaign->set($update_reenroll_campaign);
1620                    $this->UserWithdrawReenrollCampaign->save();
1621
1622                }
1623                
1624                if (
1625                    $formType == Configure::read('payment_credit_authentication') || 
1626                    $formType == Configure::read('payment_lite_credit_free') ||
1627                    $formType == Configure::read('payment_credit_chocotto_free')
1628                ) {
1629                    $this->Session->delete('PaymentCreditRegisterInfo');
1630                    // send registration completion email
1631                    App::uses('myMailer','Lib');
1632                    $mail_id = Configure::read('site_in_mail.student_registration_complete');
1633                    if ($userData &&  !in_array($userData['currency_code'], Configure::read('global_free_trail_currencies') ) ) {
1634                        $mail_id = Configure::read('site_in_mail.registration_no_trial_currencies');
1635                    }
1636                    myMailer::sendTemplateMail($mail_id, $userData['email'], $userData, array(), 'User');
1637                    //NJ-13482
1638                    $this->Session->write('payment_credit_register_complete', true);
1639                    return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_register_complete'));
1640                } else if (
1641                    $formType == Configure::read('payment_credit_force_charge') ||
1642                    $formType == Configure::read('payment_lite_credit_paid') ||
1643                    $formType == Configure::read('payment_credit_chocotto_monthly_payment')
1644                ) {
1645                    $this->Session->delete('PaymentCreditChargeInfo');
1646                    $action = 'payment_credit_charge_complete';
1647                    // if complimentary plan user before
1648                    if ($this->memcache->get('com_plan_user_'.$userData['id'])) {
1649                        $this->memcache->delete('com_plan_user_'.$userData['id']);
1650                        $action = 'coupon_payment_credit_charge_complete';
1651                    }
1652
1653                    // Teacher Perks : Student re-enroll
1654                    if ( $formType == Configure::read('payment_credit_force_charge')) {
1655                        ClassRegistry::init('TeacherPerksAccount')->reEnroll(['user_id' => $userData['id']]);
1656                    }
1657                    
1658                    //    NC-7644 Add code reward for re-enroolling with the campaign code
1659                    $this->log(__METHOD__ ."sai_debug -> Add 500 Coin Reward for re-enroll: ", "debug");
1660                    $this->addCoinRewardForReenroll($userData);
1661
1662                    // - add monthly mc coin if lite plan user 
1663                    if ($formType == Configure::read('payment_lite_credit_paid')) {
1664                        $this->liteUserAddCoinRewardForReenroll(array('id' => $userData['id']));
1665                    }
1666                    
1667                    return $this->redirect(array('controller' => 'payment', 'action' => $action));
1668                } else if ($formType == Configure::read('payment_credit_change')) {
1669                    if (isset($data["origin_redirect"]) ) {
1670                        return $this->redirect(array('controller' => 'store', 'action' => 'card_register_complete','?' => $data["origin_redirect"] ));
1671                    } else{
1672                        return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_change_complete'));
1673                    }
1674                } else if ($formType == Configure::read('payment_credit_retry')) {
1675                    // - flag manual paying user success
1676                    UserTable::saveManualPayingUsersToMemcache($userData['id']);
1677                    $this->Session->delete('PaymentCreditRetryInfo');
1678                    $this->Session->delete('PaymentCreditRetryInfoCorporateAmount');
1679                    return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_retry_complete'));
1680                } elseif (
1681                    $formType == Configure::read('payment_individual_corporate_standard') ||
1682                    $formType == Configure::read('payment_individual_corporate_premium') ||
1683                    $formType == Configure::read('payment_prepaid_corporate_light_member')
1684                ) {
1685                    $this->Session->delete('PaymentCreditChargeInfo');
1686                    $this->Session->delete('PaymentCreditChargeCorporateData');
1687                    // NJ-28462 [PC][Dev] Organize the re-enrollment behavior after corporate plan ends From bug ticket (NJ-28435)  
1688                    $this->Session->delete('corporateIndiPrices');
1689                    
1690
1691                    return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_charge_complete'));
1692                } else if ($formType == Configure::read('payment_study_abroad')) { 
1693                    
1694                    return $this->redirect(array('controller' => 'StudyAbroad', 'action' => 'payment_complete'));
1695                } else {
1696                    return $this->redirect(myTools::getUrl() . '/');
1697                }
1698            } else {
1699                // NC-3914: check if user is using new card
1700                // store to session
1701                if (
1702                    (isset($referrer) && $referrer['action'] == 'payment_credit_change') ||
1703                    (isset($data[$modelname]['zeus_card_option']) && $data[$modelname]['zeus_card_option'] == 'new')
1704                ) {
1705                    $this->Session->write('user_new_card_info', $data);
1706                }
1707                // handle errors
1708                $this->handleCreditResponseError($res, $referrer);
1709            }
1710        }
1711    }
1712
1713    /**
1714     * @api {get} /:language/payment/payment_credit_register_complete payment_credit_register_complete()
1715     * @apiName payment_credit_register_complete
1716     * @apiGroup Payment
1717     * @apiDescription This endpoint is used to redirect to the notice to user page after payment credit register complete.
1718     * 
1719     * @apiParam {String} language Language code of the user.
1720     * 
1721     * @apiSuccess {View} Redirect Redirects to {{ENV}}/account/notice_to_user.
1722     * @apiSuccess {View} Redirect Redirects to {{ENV}}/choco_camp_success if the user is in chocotto plan.
1723     * 
1724     * @apiSuccessExample Success Response:
1725     * Redirects to {{ENV}}/account/notice_to_user.
1726     * 
1727     * @apiSuccessExample Success Response Chocotto Plan:
1728     * Redirects to {{ENV}}/choco_camp_success if the user is in chocotto plan.
1729     * 
1730     * @apiSampleRequest off
1731     */
1732    public function payment_credit_register_complete() {
1733        $memKey = "pc_wp_register_card_type_{$this->sharedUserData['User']['api_token']}";
1734        $counselingModalMemKey = 'counseling_modal_flg'.$this->Auth->user('id');
1735
1736        // delete if memcache exist
1737        if ($this->memcache->get($memKey)) {
1738            $this->memcache->delete($memKey);
1739        }
1740
1741        if ($this->memcache->get($counselingModalMemKey)) {
1742            $this->memcache->delete($counselingModalMemKey);
1743        }
1744
1745        $userId = $this->Auth->user('id');
1746        $coinData = array(
1747            "status" => false,
1748            "ref" => $userId
1749        );
1750        $this->Session->write("coinReadRefStatus", $coinData);
1751
1752        //NJ-13482
1753        $this->Session->write('reenroll_native_option', true);
1754
1755        //- NJ-27262 chocotto plans redirect
1756        if (in_array($this->sharedUserData['User']['payment_plan_id'], [
1757            Configure::read('payment_plans.free_trial_chocotto'),
1758            Configure::read('payment_plans.chocotto_plan')
1759        ])) {
1760            return $this->redirect('/chocotto_camp_success');
1761        }
1762        return $this->redirect(array('controller' => 'account', 'action' => 'notice_to_user'));
1763    }
1764    /**
1765     * @api {get} /:language/payment/coupon_payment_credit_charge_complete coupon_payment_credit_charge_complete()
1766     * @apiName coupon_payment_credit_charge_complete
1767     * @apiGroup Payment
1768     * @apiDescription This endpoint is used to redirect payment credit charge complete page after using coupon.
1769     * 
1770     * @apiParam {String} language Language code of the user.
1771     * 
1772     * @apiSuccess {View} Render Renders the payment credit charge complete page.
1773     * 
1774     * @apiSuccessExample Success Response:
1775     * Renders the payment credit charge complete page.
1776     * 
1777     * @apiSampleRequest off
1778     */
1779    public function coupon_payment_credit_charge_complete() {
1780        $this->set('comPlanBefore', true);
1781        $this->payment_credit_charge_complete();
1782    }
1783
1784    /**
1785     * @api {get} /:language/payment/payment_credit_charge_complete payment_credit_charge_complete()
1786     * @apiName payment_credit_charge_complete
1787     * @apiGroup Payment
1788     * @apiDescription This endpoint is used to display the credit card charge complete page.
1789     * 
1790     * @apiParam {String} language Language code of the user.
1791     * 
1792     * @apiSuccess {View} Render Renders the credit card charge complete page.
1793     * @apiSuccess {View} Render Renders the mobile credit card charge complete page if the user is using mobile.
1794     * @apiSuccess {View} Redirect Redirects to {{ENV}}/register/chocotto_camp_success if the user is in chocotto plan.
1795     * 
1796     * @apiError {View} Redirect Redirects to {{ENV}}//account
1797     * 
1798     * @apiSuccessExample Success Response PC:
1799     * Renders the credit card charge complete page.
1800     * 
1801     * @apiSuccessExample Success Response Mobile:
1802     * Renders the mobile credit card charge complete page.
1803     * 
1804     * @apiSuccessExample Success Response Chocotto Plan:
1805     * Redirects to {{ENV}}/register/chocotto_camp_success if the user is in chocotto plan.
1806     * 
1807     * @apiErrorExample Error Response:
1808     * Redirects to {{ENV}}//account
1809     * 
1810     * @apiSampleRequest off
1811     */
1812    public function payment_credit_charge_complete(){
1813        $this->set('title_for_layout', '登録完了|オンライン英会話のネイティブキャンプ');
1814        $user = $this->sharedUserData['User'];
1815
1816        $memKey = "pc_wp_charge_card_type_{$user['api_token']}";
1817        // delete memcache
1818        if ($this->memcache->get($memKey)) {
1819            $this->memcache->delete($memKey);
1820        }
1821
1822        if ($this->Session->read('complimentaryToPlan')) {
1823            $this->Session->delete('complimentaryToPlan');
1824        }
1825
1826        $this->set('nickname', $user['nickname']);
1827        if ($this->RequestHandler->isMobile()) {
1828            $this->layout = ('mobile');
1829            $this->render('/Mobile/Reregister/payment_credit_charge_complete');
1830        } else {
1831            $this->render('/Payment/payment_credit_charge_complete');
1832        }
1833
1834        $userId = $user['id'] ?? "";
1835
1836        // NJ-33414 Update Lesson Request to Default
1837        $this->UsersDetail->openDBReplica();
1838        $usersDetail = $this->UsersDetail->find('first', array(
1839            'fields' => array('lesson_request_flg'),
1840            'conditions' => array('UsersDetail.user_id' => $userId),
1841            'recursive' => -1
1842        ));
1843        $this->UsersDetail->closeDBReplica();
1844
1845        if( $usersDetail ) {
1846            $this->UsersDetail->clear();
1847            $this->UsersDetail->query("
1848                    UPDATE
1849                        `english`.`users_detail`
1850                    SET
1851                        lesson_request_flg = 1
1852                    WHERE
1853                        user_id = {$user['id']}
1854            ");
1855
1856            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - update user_detail lesson_request_flg to 1', 'error');
1857        } else {
1858            $this->UsersDetail->clear();
1859            $this->UsersDetail->set([
1860                'user_id' => $user['id'],
1861                'individual_card_fail_flg'    => 0,
1862                'lesson_request_flg' => 1
1863            ]);
1864            $this->UsersDetail->validate = [];
1865            $this->UsersDetail->save();
1866
1867            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - add user detail with individual_card_fail_flg to 0 and lesson_request_flg to 1', 'error');
1868        }
1869
1870        // NJ-23812 : redirect to url if url is from /account re-register
1871        $sessionParams = array(
1872            'result' => true,
1873            'auth_bonus_coin' => 0,
1874            'is_register_card' => false
1875        );
1876
1877        // NJ-23812: update user payment plan data ?
1878        $userData = $this->User->find('first', array(
1879            'fields' => array(
1880                'id',
1881                'payment_plan_id',
1882                'corporate_type',
1883            ),
1884            'conditions' => array('id' => $user['id']),
1885            'recursive' => -1
1886        ));
1887
1888        if ($userData) {
1889            $corpType = myTools::getCoporateTypeUsingPaymentPlanId($userData['User']['payment_plan_id']);
1890            $this->sharedUserData['User']['payment_plan_id'] = $userData['User']['payment_plan_id'];
1891            $this->sharedUserData['User']['corporate_type'] = $corpType;
1892        }
1893
1894        // NJ-23812 : skip  show welcome back modal
1895        $this->Session->write('show_welcome_back_modal',$sessionParams);
1896
1897        //-chocotto plan logout user
1898        if ($userData['User']['payment_plan_id'] == Configure::read('payment_plans.chocotto_plan')) {
1899            $this->Auth->logout();
1900            return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/register/chocotto_camp_success");
1901        }
1902        return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/account");
1903    }
1904
1905    /**
1906     * @api {get} /:language/payment/payment_credit_retry_complete payment_credit_retry_complete()
1907     * @apiName payment_credit_retry_complete
1908     * @apiGroup Payment
1909     * @apiDescription This endpoint is used to redirect to account after payment credit retry complete.
1910     * 
1911     * @apiParam {String} language Language code of the user.
1912     * 
1913     * @apiSuccess {View} Redirect Redirects to {{ENV}}/account.
1914     * 
1915     * @apiSuccessExample Success Response:
1916     * Redirects to {{ENV}}/account.
1917     * 
1918     * @apiSampleRequest off
1919     */
1920    public function payment_credit_retry_complete(){
1921        $user = $this->sharedUserData['User'];
1922        $this->set('nickname', $user['nickname']);
1923
1924        // ~ process child receivable
1925        $childsDetail = $this->User->getChildsDetail($user['id']);
1926
1927        if (!empty($childsDetail)) {
1928            foreach ($childsDetail as $detail) {
1929                $this->processChildReceivablePayment($detail['User'], $user);
1930            }
1931        }
1932
1933        $memKey = "pc_wp_retry_card_type_{$user['api_token']}";
1934        // delete memcache
1935        if ($this->memcache->get($memKey)) {
1936            $this->memcache->delete($memKey);
1937        }
1938
1939        // NJ-23812 : redirect to url if url is from /account re-register
1940            $sessionParams = array(
1941                'result' => true,
1942                'auth_bonus_coin' => 0,
1943                'is_register_card' => false
1944            );
1945
1946            // NJ-23812 : skip  show welcome back modal
1947            $this->Session->write('show_welcome_back_modal',$sessionParams);
1948            return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/account");
1949    }
1950
1951    /**
1952     * @api {get} /:language/payment/payment_credit_change_complete payment_credit_change_complete()
1953     * @apiName payment_credit_change_complete
1954     * @apiGroup Payment
1955     * @apiDescription This endpoint is used to display the credit card change complete page.
1956     * 
1957     * @apiParam {String} language Language code of the user.
1958     * 
1959     * @apiBody {String} page_origin The page origin of the request.
1960     * 
1961     * @apiSuccess {View} Render Renders the credit card change complete page.
1962     * 
1963     * @apiError {View} Redirect Redirects to {{ENV}}/account if the page origin is not found.
1964     * 
1965     * @apiExample Example usage:
1966     * {
1967     *         "page_origin": "account"
1968     * }
1969     * 
1970     * @apiSuccessExample Success Response:
1971     * Renders the credit card change complete page.
1972     * 
1973     * @apiErrorExample Error Response:
1974     * Redirects to {{ENV}}/account if the page origin is not found.
1975     * 
1976     * @apiSampleRequest off
1977     */
1978    public function payment_credit_change_complete(){
1979        $memKey = "pc_wp_change_{$this->sharedUserData['User']['api_token']}";
1980        // delete memcache
1981        if ($this->memcache->get($memKey)) {
1982            $this->memcache->delete($memKey);
1983        }
1984
1985        $url = "/account";
1986        $platform = "pc";
1987        $requestData = $this->request->query;
1988
1989        if ( isset($requestData['page_origin']) ) {
1990            $useUrlArr = Configure::read('change_credit_card_redirect.url');
1991            if ( isset($useUrlArr[$platform][$requestData['page_origin']]) ) {
1992                $url = $useUrlArr[$platform][$requestData['page_origin']];
1993            }
1994        }
1995
1996        // NJ-23812 : redirect to url if url is from /account re-register
1997        if ($url == "/account") {
1998            return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/account");
1999        }
2000
2001
2002        $this->set('url', $url );
2003        $this->set('title_for_layout', 'クレジット情報変更完了|オンライン英会話のネイティブキャンプ');
2004    }
2005
2006    /**
2007     * @api {get} /payment/handleCreditResponseError/:res/:referrer
2008     * @apiName handleCreditResponseError
2009     * @apiGroup Payment
2010     * @Description This endpoint is used to point out errors and returns it from the referrer url.
2011     * 
2012     * @apiParam {String} res The response from the credit card charge.
2013     * @apiParam {String} referrer The referrer url
2014     * 
2015     * @apiSuccess {String} error The error message
2016     * @apiSuccess {View} Redirect Redirects to the referrer url / home page if referrer url is not found
2017     * 
2018     * @apiSuccessExample Success Response Settlement Failure:
2019     * Error : 決済失敗
2020     * Redirects to the referrer url or home page
2021     * 
2022     * @apiSuccessExample Success Response Under Maintenance:
2023     * Error : メンテナンス中
2024     * Redirects to the referrer url or home page
2025     * 
2026     * @apiSuccessExample Success Response Connect Error:
2027     * Error : Connect Error
2028     * Redirects to the referrer url or home page
2029     * 
2030     * @apiSuccessExample Success Response Invalid Card Number:
2031     * Error : カード番号が正しくありません 半角数字で入力してください。ハイフン(-)は必要ありません。
2032     * Redirects to the referrer url or home page
2033     * 
2034     * @apiSuccessExample Success Response Invalid Telephone Number:
2035     * Error : 電話番号が正しくありません 半角数字で入力してください。ハイフン(-)は必要ありません。
2036     * Redirects to the referrer url or home page
2037     * 
2038     * @apiSuccessExample Success Response Invalid Username:
2039     * Error : クレジットカードに記載されている名前を半角英字で入力してください。
2040     * Redirects to the referrer url or home page
2041     * 
2042     * @apiSuccessExample Success Response Invalid Client IP:
2043     * Error : 決済失敗
2044     * Redirects to the referrer url or home page
2045     * 
2046     * @apiSuccessExample Success Response Other Errors:
2047     * Error : $res
2048     * Redirects to the referrer url or home page
2049     * 
2050     * @apiSampleRequest off
2051     */
2052    public function handleCreditResponseError($res, $referrer){
2053        // errors
2054        $error = "";
2055        $failureOrder = "failure_order";
2056        $maintenance = "maintenance";
2057        $connectError = "connect error";
2058        $cardNumberError = "Invalid Cardnumber";
2059        $telnoError = "Invalid telno";
2060        $usernameError = "Invalid username";
2061        $invalidClientIp = "Invalid clientip";
2062        
2063        // check error message
2064        if ($res[0] == $failureOrder || $res == $failureOrder) {
2065            $error = __("Error : 決済失敗");
2066        } else if ($res[0] == $maintenance || $res == $maintenance) {
2067            $error = __("Error : メンテナンス中");
2068        } else if ($res[0] == $connectError || $res == $connectError) {
2069            $error = __("Error : Connect Error");
2070        } else if ($res[0] == $cardNumberError || $res == $cardNumberError) {
2071            $error = __("Error : カード番号が正しくありません 半角数字で入力してください。ハイフン(-)は必要ありません。");
2072        } else if ($res[0] == $telnoError || $res == $telnoError) {
2073            $error = __("Error : 電話番号が正しくありません 半角数字で入力してください。ハイフン(-)は必要ありません。");
2074        } else if ($res[0] == $usernameError || $res == $usernameError) {
2075            $error = __("Error : クレジットカードに記載されている名前を半角英字で入力してください。");
2076        } else if ($res[0] == $invalidClientIp || $res == $invalidClientIp) {
2077            $error = __("Error : 決済失敗");
2078        } else {
2079            $error = $res;
2080        }
2081
2082        // set the flash message
2083        $this->Session->setFlash($error, array("element" => "flashfail"));
2084        
2085        // check if the referrer action exists
2086        if (is_array($referrer)) {
2087            return $this->redirect($referrer);
2088        } else {
2089            return $this->redirect(myTools::getUrl() . '/');
2090        }
2091    }
2092
2093    /**
2094     * @api {post} /payment/zeuspay/:zeus3DsecureFlg/:ordd/:money/:sendid/:email/:clientip/:sendpoint/:result/:paymentType/:formType/:payment_id/:cardnumber/:cardbrand zeuspay()
2095     * @apiName zeuspay
2096     * @apiGroup Payment
2097     * @apiDescription This endpoint is used to handle the payment process using zeuspay.
2098     * 
2099     * @apiParam {Boolean} zeus3DsecureFlg The 3D secure flag.
2100     * @apiParam {String} ordd The order id.
2101     * @apiParam {Number} money The amount of money.
2102     * @apiParam {String} sendid The user id.
2103     * @apiParam {String} email The user email.
2104     * @apiParam {String} clientip The client ip address.
2105     * @apiParam {String} sendpoint The payment hash.
2106     * @apiParam {String} result The result of the payment.
2107     * @apiParam {Number} paymentType The payment type.
2108     * @apiParam {Number} formType The form type.
2109     * @apiParam {Number} payment_id The payment id.
2110     * @apiParam {Number} cardnumber The card number.
2111     * @apiParam {String} cardbrand The card brand.
2112     * 
2113     * @apiSuccess {Database} Save Save/update the payment transaction to the database.
2114     * 
2115     * @apiError {PHP} slackZeusErrorPostMsg Sends a slack message if the source IP is not supported.
2116     * @apiError {PHP} log Logs the error if the payment hash is not set.
2117     * 
2118     * @apiSuccessExample Success Response Textbook Purchase:
2119     * Updates the textbook_sales table, inserts the payment_id
2120     * 
2121     * @apiSuccessExample Success Response Payment Receivable:
2122     * creates new payment in payment table and update/add user's settlement amount
2123     * 
2124     * @apiSuccessExample Success Response Appreciation Receivable:
2125     * creates new payment in payment table and update/add user's settlement amount
2126     * 
2127     * @apiSuccessExample Success Response Native Speaker Payment:
2128     * creates new payment in payment table and update/add user's settlement amount
2129     * 
2130     * @apiSuccessExample Success Response Callan Option Payment:
2131     * creates new payment in payment table and update/add user's settlement amount
2132     * 
2133     * @apiErrorExample Error Response Source IP not supported:
2134     * Sends a slack message if the source IP is not supported.
2135     * 
2136     * @apiErrorExample Error Response Payment Hash not set:
2137     * Logs the error if the payment hash is not set.
2138     * 
2139     * @apiSampleRequest off
2140     */
2141    public function zeuspay() {
2142
2143        $this->autoLayout = false;
2144        $this->autoRender = false;
2145
2146        App::uses('telecomcheckout','Vendor');
2147
2148        # get data
2149        $data = $this->request->query;
2150        $zeus3DSecureFlg = isset($data['zeus3DSecureFlg']) && $data['zeus3DSecureFlg'] ? true : false;
2151        
2152        // - debug
2153        if (
2154            // - if has ordd or money
2155            isset($data["ordd"]) && 
2156            isset($data["money"]) && 
2157            
2158            // - if valid ordd
2159            $data["ordd"] &&
2160            
2161            // - if valid money
2162            $data["money"] > 0
2163        ) {
2164            // - get first slack segment
2165            $slackSegments = explode("-", $data["ordd"]);
2166            
2167            // - if test card
2168            if (
2169                // - if dev, staging, local
2170                in_array(Configure::read('ENVIRONMENT'), ["DEV", "STAGING", "LOCAL"])
2171                
2172                // - not a test card
2173                && !in_array($slackSegments[0], ["TEST", "CHECK"])
2174            ) {
2175                // - send slack
2176                $mySlack = new mySlack();
2177                $mySlack->channel = myTools::checkChannel("#fdci-nativecamp", "#fdci-nativecamp");
2178                $mySlack->link_names = true;
2179                $mySlack->allow_test_channel = true;
2180                $mySlack->token = "xoxb-392902820692-6499139810404-RHHGc6Z5ZB9o2KkiGhzTTtlQ";
2181                $mySlack->text = "<!subteam^SNX2TCYAE|fdci-delivery>";
2182                $mySlack->text .= "```";
2183                $mySlack->text .= "environment: " . json_encode(Configure::read('ENVIRONMENT')) ."\n\n";
2184                $mySlack->text .= "user_id: " . ($data['sendid']) ."\n";
2185                $mySlack->text .= "email: " . ($data['email']) ."\n";
2186                $mySlack->text .= "amount: " . ($data['money']);
2187                $mySlack->text .= "```";
2188                $mySlack->postMessage();
2189            }
2190        }
2191        
2192        // check if from a valid ip address and not 3d secure callback
2193        if(
2194            !$zeus3DSecureFlg && 
2195            $_SERVER["REMOTE_ADDR"] != "210.164.6.67" && 
2196            $_SERVER["REMOTE_ADDR"] != "202.221.139.50" && 
2197            $_SERVER["REMOTE_ADDR"] != "180.232.127.154" &&
2198            $_SERVER["REMOTE_ADDR"] != "133.242.229.199"
2199        ){
2200            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, 0, 'Source IP not supported', $data);
2201            die;
2202        }
2203
2204        # load model
2205        $this->loadModel("ZPaymentSucceeded");
2206        $this->loadModel("UsersPoint");
2207        $this->loadModel("Payment");
2208        $this->loadModel("ContinuationCampaign");
2209        
2210        # set variables
2211        $telecom_zeus_convert = false;
2212        $formType = Configure::read('payment_credit_default');
2213        $card_company = Configure::read('card_company.zeus');
2214        $platform = Configure::read('platform.pclp');
2215        $receivablePayment = $liveLessonReceivable = 0;
2216        $dateNow = date("Y-m-d H:i:s");
2217        $appreciationFlg = 0;
2218        $tipAmount = null;
2219
2220        // if payment hash is not set
2221        if (!isset($data['sendpoint'])) {
2222            $this->log(__METHOD__ . ' zeus.error.no_payment_hash', 'debug');
2223            $this->_error_log_set($data);
2224            return ;
2225        }
2226
2227        // if using corporate company payment (credit card)
2228        if (strpos($data['sendid'], 'cz') !== false) {
2229            $data['usingCompanyCard'] = true;
2230            return $this->corporateZeuspay($data);
2231        }
2232
2233        // - check if paymentHash is empty
2234        if (
2235            (isset($data['result']) && strtoupper($data['result']) == "OK") &&
2236            (!$data['sendpoint'] || $data['sendpoint'] == 0) && 
2237            (isset($data['sendid']) && $data['sendid'])
2238        ) {
2239            $data['sendpoint'] = $this->memcache->get('zeus_sec_payment_hash_'.$data['sendid']);
2240        }
2241
2242        // get payment hash
2243        $paymentHash = trim($data['sendpoint']);
2244
2245        // prevent switching to replicas inside kickback
2246        $this->PaymentTransaction->setOverrideConnectFlg(true);
2247
2248        // get payment transaction
2249        $ptData = $this->PaymentTransaction->getWPPaymentTransaction($paymentHash);
2250
2251        // if pending payment transaction does not exist try to remove condition to check if has failed transation to override it
2252        if (!$ptData && strtoupper($data['result']) == 'OK') {
2253            // override the last transaction
2254            $ptData = $this->PaymentTransaction->find('first', array(
2255                'fields' => array(
2256                    'id',
2257                    'user_id',
2258                    'password',
2259                    'payment_params'
2260                ),
2261                'conditions' => array(
2262                    'payment_hash' => $paymentHash
2263                ),
2264                'recursive' => -1
2265            ));
2266
2267            if ($ptData) {
2268                $ptData = $ptData['PaymentTransaction'];
2269            }
2270        }
2271
2272        // do nothing if payment transaction (payment hash and status = 0) does not exist.
2273        if (!$ptData) {
2274            $this->log(__METHOD__ . ' Payment transaction status 0 does not exist. ' . json_encode($data), 'monthly_payment');
2275            // Send to slack only if money is greater than 0
2276            if (isset($data['money']) && $data['money'] > 0) {
2277                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, 0, 'Payment transaction status 0 does not exist', $data);
2278            }
2279            return ;
2280        }
2281
2282        // decode payment params to array
2283        $ptPaymentParams = json_decode($ptData['payment_params'], true);
2284        $familyId = isset($ptPaymentParams['familyId']) ? $ptPaymentParams['familyId'] : null;
2285        $userId = $familyId ? $familyId : $data['sendid'];
2286        $cardExpirationDate = isset($data['cardexpirationdate']) ? $data['cardexpirationdate'] : null;
2287        $logFileName = isset($ptPaymentParams['logFileName']) ? $ptPaymentParams['logFileName'] : 'monthly_payment';
2288        $basicFee = isset($ptPaymentParams['basicFee']) ? $ptPaymentParams['basicFee'] : 0;
2289        $lessonFee = isset($ptPaymentParams['lessonFee']) ? $ptPaymentParams['lessonFee'] : 0;
2290        $lessonFeeDateStarted = isset($ptPaymentParams['lessonFeeDateStarted']) ? $ptPaymentParams['lessonFeeDateStarted'] : null;
2291        $ptId = $ptData['id'];
2292        
2293        //remove from paying users memcache
2294        UserTable::removePayingUserFromMemcache($userId);
2295
2296        # check the source of the payment
2297        if (isset($ptPaymentParams['formType'])) {
2298            $formType = $ptPaymentParams['formType'];
2299        }
2300
2301        // prevent switching to replicas inside kickback
2302        $this->Payment->setOverrideConnectFlg(true);
2303        
2304        $monthlyPaymentExist = $this->Payment->find('count', array(
2305            'conditions' => array(
2306                'Payment.user_id' => $userId,
2307                'Payment.ordd' => $data['ordd'],
2308                'Payment.card_company' => Configure::read('card_company.zeus'),
2309                'Payment.form_type' => $formType
2310            )
2311        ));
2312        
2313        // NC-4036: do nothing if zeus user and monthly payment transaction (ordd) already exist.
2314        if ($monthlyPaymentExist) {
2315            $this->log(__METHOD__ . ' Payments data already exist. ' . json_encode($data), $logFileName);
2316            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Payments data already exist', $data);
2317            return ;
2318        }
2319
2320        // NC-8600: if family is withdrawn
2321        if ($formType == Configure::read('payment_credit_family_monthly_payment') && $this->memcache->get('deactivated-user-'.$userId)) {
2322            $this->log(__METHOD__ . ' User is withdrawn. ' . json_encode($data), 'monthly_payment');
2323            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'User is withdrawn', $data);
2324            return;
2325        }
2326        
2327        // save settlement history for tracking
2328        if (!SettlementHistoryTable::add(array(
2329                'userId' => $userId,
2330                'params' => json_encode($data),
2331                'createdIp' => $dateNow,
2332                'modifiedIp' => $dateNow
2333            )
2334        )) {
2335            $this->log(__METHOD__ . ' Failed to save zeuspay kickback data in settlement history. ' . json_encode($data), $logFileName);
2336            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save zeuspay kickback data in settlement history', $data);
2337            return;
2338        }
2339
2340        # append data parameters
2341        $data += array(
2342                'ip' => isset($ptPaymentParams['remoteAddress']) ? $ptPaymentParams['remoteAddress'] : null,
2343                'user_id' => $userId,
2344                'created' => $dateNow,
2345                'modified' => $dateNow,
2346        );
2347
2348        # check if user exists, and remove any bound models
2349        $userData = $this->User->find("first",array("conditions" =>array("User.id"=>$userId), "recursive" => -1));
2350        if (!$userData) {
2351            $this->log(__METHOD__ . ' User id does not exist. ' . json_encode($userId) . ' -- ' . json_encode($data), $logFileName);
2352            $data['error_code'] = Configure::read('zeus.error.no_user');
2353            $this->_error_log_set($data, $ptPaymentParams);
2354            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'User id does not exist', $data);
2355            return ;
2356        }
2357
2358        $membershipStatusIndex = UserTable::getStudentMembershipStatus($userId);
2359
2360        $paymentPlanId = isset($ptPaymentParams['paymentPlanId']) ? $ptPaymentParams['paymentPlanId'] : null;
2361
2362        if (isset($data['result']) && strtoupper($data['result']) == 'OK' && $membershipStatusIndex == 7) {
2363            $this->mySlack->channel = $this->slackChannel;
2364            $this->mySlack->username = "Zeus kickback:";
2365            $this->mySlack->text = "```";
2366            $this->mySlack->text .= date("Y/m H:i") . "\n";
2367            $this->mySlack->text .= "User : " . myTools::getUrl() . '/admin/user-manage/member/' . $userData['User']['id'] . "\n";
2368            $this->mySlack->text .= "kickback arrive on deleted user";
2369            $this->mySlack->text .= "```";
2370
2371            // send slack
2372            $this->mySlack->sendSlack();
2373        }
2374
2375        if (
2376                $paymentPlanId &&
2377                in_array(
2378                        $paymentPlanId,
2379                        array(
2380                                Configure::read('payment_plans.premium_plan'),
2381                                Configure::read('payment_plans.family_plan'),
2382                                Configure::read('payment_plans.light_plan'),
2383                                Configure::read('payment_plans.chocotto_plan')
2384                        )
2385                ) &&
2386                isset($userData['User']['corporate_id']) &&
2387                $userData['User']['corporate_id'] &&
2388                !empty($userData['User']['corporate_id']) &&
2389                in_array(
2390                        $formType,
2391                        array(
2392                                Configure::read('payment_credit_force_charge'),
2393                                Configure::read('payment_lite_credit_paid'),
2394                                Configure::read('payment_credit_chocotto_free'),
2395                                Configure::read('payment_credit_chocotto_monthly_payment'),
2396                                Configure::read('payment_credit_chocotto_retry'),
2397                                Configure::read('payment_credit_chocotto_force_charge')
2398                                )
2399                )
2400        ) {
2401            // - removed corporate id
2402            $userData['User']['corporate_id'] = null;
2403            $this->User->read(array('corporate_id'), $userId);
2404            $this->User->set(array('corporate_id' => ''));
2405            $this->User->validate = array();
2406            $this->User->save();
2407        }
2408
2409        // redirect to corporate zeuspay if corporate individual user
2410        // and form type is not equals to force charge
2411        if (
2412            isset($userData['User']['corporate_id']) &&
2413            $userData['User']['corporate_id'] &&
2414            !in_array($formType, array(Configure::read('payment_credit_force_charge'),Configure::read('payment_lite_credit_paid') , Configure::read('payment_credit_chocotto_force_charge'),Configure::read('payment_study_abroad') ) )
2415        ) {
2416            return $this->corporateZeuspay($data, true);
2417        }
2418
2419        # check if ordd is present
2420        if (isset($data['ordd']) === FALSE) {
2421            $data['ordd'] = NULL;
2422        }
2423
2424        # check clientip if url is from zeus
2425        if ($data['clientip'] == Configure::read('ZEUS_clientip')) {
2426            $card_company = Configure::read('card_company.zeus');
2427        }
2428
2429        # check if payment transaction password exist
2430        $ptPassword = "";
2431        if (isset($ptData['password'])) {
2432            $ptPassword = $ptData['password'];
2433        }
2434
2435        # check if payment type is from payment plan or coin purchase or textbook purchase
2436        if (isset($ptPaymentParams['paymentType'])) {
2437            $paymentType = $ptPaymentParams['paymentType'];
2438        }
2439
2440        # check platform
2441        if (isset($ptPaymentParams['platform'])) {
2442            $platform = $ptPaymentParams['platform'];
2443        }
2444
2445        $priceId = isset($ptPaymentParams['priceId']) ? $ptPaymentParams['priceId'] : null;
2446        $currencyCode = isset($ptPaymentParams['currencyCode']) ? $ptPaymentParams['currencyCode'] : Configure::read('currency_jpy');
2447        $discounted_amount = isset($ptPaymentParams['discounted_amount']) ? $ptPaymentParams['discounted_amount'] : 0;
2448
2449        // if using coupon during force settlement
2450        if (!empty($ptPaymentParams['couponUseSettlement']) && !empty($ptPaymentParams['couponUseSettlement']['useCouponAmount']) && in_array($formType, Configure::read('allow_coupon.settlement_form_type'))) {
2451            $discounted_amount += $ptPaymentParams['couponUseSettlement']['useCouponAmount'];
2452        }
2453
2454        # NC-8194: check null payment_plan_id and price_id
2455        if (!$paymentPlanId || !$priceId) {
2456            if ( $userData['User']['payment_plan_id'] && $userData['User']['price_id']) {
2457                $paymentPlanId = $userData['User']['payment_plan_id'];
2458                $priceId = $userData['User']['price_id'];
2459            } else {
2460                $defPlan = $this->PaymentPlanPrice->getDefaultPlan($userData['User']);
2461                $paymentPlanId = $defPlan['paymentPlanId'];
2462                $priceId = $defPlan['priceId'];
2463            }
2464        }
2465
2466        # set data variables
2467        $data['paymentType'] = $paymentType;
2468        $data['formType'] = $formType;
2469
2470        // - NJ-18780 : check if lite plan user 
2471        $isLitePlanUser = in_array($paymentPlanId, Configure::read('lite_payment_plans')) ? true : false;
2472
2473        $cronDateRun = $dateNow;
2474        // hotfix_NC-3152: add cronDateRun
2475        if (isset($ptPaymentParams['cronDateRun'])) {
2476            $cronDateRun = date('Y-m-d 00:20:00');
2477        }
2478
2479        $monthlyPayment = isset($data["money"]) ? $data["money"] : 0;
2480        $nativeOptionPayment = 0;
2481        $callanOptionPayment = 0;
2482
2483        
2484        // if monthly payment, retry or force charge
2485        // check if user has receivable payment
2486        if (in_array($formType, array(
2487            Configure::read('payment_credit_monthly_payment'),
2488            Configure::read('payment_credit_family_monthly_payment'),
2489            Configure::read('payment_credit_force_charge'),
2490            Configure::read('payment_credit_retry'),
2491            Configure::read('payment_lite_credit_monthly_payment'),
2492            Configure::read('payment_lite_credit_paid'),
2493            Configure::read('payment_lite_plan_downgrade'),
2494            Configure::read('payment_lite_plan_upgrade'),
2495            Configure::read('payment_credit_change'),
2496            Configure::read('payment_credit_chocotto_monthly_payment'),
2497            Configure::read('payment_credit_chocotto_retry'),
2498            Configure::read('payment_credit_chocotto_force_charge')
2499        ))) {
2500
2501            $_allowChangePlan = true;
2502
2503            if (
2504                $formType == Configure::read('payment_lite_plan_downgrade') || 
2505                $formType == Configure::read('payment_lite_plan_upgrade')
2506            ) {
2507                $_allowChangePlan = false;// default 
2508
2509                if (isset($ptPaymentParams['changePlanChargeFlg']) && $ptPaymentParams['changePlanChargeFlg']) {
2510                    $_allowChangePlan = true;
2511                }
2512            }
2513
2514            // compute receivable payments
2515            $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userData['User']['id'], $cronDateRun);
2516
2517            // if has receivable payment
2518            // deduct said monthly settlement from the money sent to zeus
2519            if ($receivablePayment && $receivablePayment <= $data["money"] && $_allowChangePlan) {
2520                // deduct from monthly payment
2521                $monthlyPayment -= $receivablePayment;
2522            }
2523
2524            // if has native speaker payments
2525            // deduct
2526            if (isset($ptPaymentParams['nativeOptionPayment']) && $ptPaymentParams['nativeOptionPayment'] > 0 && $_allowChangePlan) {
2527                $nativeOptionPayment = $ptPaymentParams['nativeOptionPayment'];
2528                $monthlyPayment -= $nativeOptionPayment;
2529            }
2530
2531            // if has callan option payments
2532            // deduct
2533            if (isset($ptPaymentParams['callanOptionPayment']) && $ptPaymentParams['callanOptionPayment'] > 0 && $_allowChangePlan) {
2534                $callanOptionPayment = $ptPaymentParams['callanOptionPayment'];
2535                $monthlyPayment -= $callanOptionPayment;
2536            }
2537
2538            // compute appreciation receivable payments
2539            $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.appreciation'));
2540
2541            if ($appreciationReceivable && $appreciationReceivable <= $monthlyPayment) {
2542                $monthlyPayment -= $appreciationReceivable;
2543            }
2544
2545            // compute live lesson receivable payments
2546            $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userData['User']['id'], $cronDateRun, Configure::read('payment_element_type.live'));
2547
2548            if ($liveLessonReceivable && $liveLessonReceivable <= $monthlyPayment && $_allowChangePlan) {
2549                $monthlyPayment -= $liveLessonReceivable;
2550            }            
2551
2552            $ptPaymentParams['paymentAmount'] = $monthlyPayment;
2553        }
2554
2555        // Check receivables combine on `payment_credit_receivable` form type
2556        if( $formType == Configure::read('payment_credit_receivable') ) {
2557
2558            // compute appreciation receivable payments
2559            $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.appreciation'));
2560
2561            // deduct said receivable settlement from the money sent to zeus
2562            if ($appreciationReceivable && $appreciationReceivable <= $data["money"]) {
2563                // deduct from receivable payment
2564                $monthlyPayment -= $appreciationReceivable;
2565            }
2566
2567            // compute live receivable payments
2568            $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.live'));
2569
2570            // deduct said receivable settlement from the money sent to zeus
2571            if ($liveLessonReceivable && $liveLessonReceivable <= $data["money"]) {
2572                // deduct from receivable payment
2573                $monthlyPayment -= $liveLessonReceivable;
2574            }            
2575
2576            $ptPaymentParams['paymentAmount'] = $monthlyPayment;
2577        }
2578
2579        $kbResult = false;
2580        # check if the result is ok
2581        if ( strtoupper($data['result']) == 'OK' ) {
2582            $kbResult = true;
2583            $this->log(__METHOD__ . 'result is ok', $logFileName);
2584
2585            # get current card company
2586            $currentCardCompany = is_null($userData['User']['card_company']) ? FALSE : intVal($userData['User']['card_company']);
2587
2588            # if user is with telecom, withdraw
2589            if (
2590                (
2591                    $formType != Configure::read('payment_credit_coin_purchase') && 
2592                    $formType != Configure::read('payment_credit_textbook_purchase') && 
2593                    $formType != Configure::read('payment_credit_receivable') &&
2594                    $formType != Configure::read('payment_credit_appreciation_receivable') &&
2595                    $formType != Configure::read('payment_native_option_join') &&
2596                    $formType != Configure::read('payment_native_option_monthly_payment') &&
2597                    $formType != Configure::read('payment_callan_option_join') &&
2598                    $formType != Configure::read('payment_callan_option_monthly_payment') &&
2599                    $formType != Configure::read('payment_study_abroad')
2600                ) &&
2601                $currentCardCompany !== FALSE &&
2602                $currentCardCompany == Configure::read('card_company.telecom')
2603            ) {
2604                # perform withdrawal
2605                $telecom = new telecomcheckout();
2606
2607                # get past payment transactions
2608                $paymentTransaction = $this->PaymentTransaction->find("all",
2609                    array(
2610                        "conditions" => array (
2611                            "user_id" => $userData['User']["id"]
2612                        ),
2613                        "order" => "id ASC"
2614                    )
2615                );
2616
2617                # check if payment transactions exists
2618                if ($paymentTransaction) {
2619                    # loop through each payment transactions
2620                    foreach ( $paymentTransaction as $sendpass) {
2621                        # set telecom params
2622                        $telecom->setParams(array(
2623                                'sendid'   => $userData['User']['hash16'],
2624                                'sendpass' => $sendpass["PaymentTransaction"]["password"],
2625                        ));
2626
2627                        # get result
2628                        $res = $telecom->setDeactivation();
2629
2630                        # check if withdrawal from telecom was ok
2631                        if (strtoupper($res) === 'OK') {
2632                            $this->User->set('id', $userData['User']['id']);
2633                            $this->User->set('charge_flg', 0);
2634                            $this->User->set('card_company', $card_company);
2635                            $this->User->set('modified', date('YmdHis'));
2636                            $this->User->save();
2637                            $telecom_zeus_convert = true;
2638                            break;
2639                        }
2640                    }
2641                }
2642
2643                # check if the conversion worked
2644                if($telecom_zeus_convert == false){
2645                    $this->mySlack->channel = $this->slackChannel;
2646                    $this->mySlack->username = "Payment Withdrawal :";
2647                    $this->mySlack->text = "```";
2648                    $this->mySlack->text .= date("Y/m H:i") . "\n";
2649                    $this->mySlack->text .= "User : " . $userData['User']['id'] . "\n";
2650                    $this->mySlack->text .= "Withdrawal failed. Please withdraw manually.";
2651                    $this->mySlack->text .= "```";
2652
2653                    // send slack
2654                    $this->mySlack->sendSlack();
2655
2656                    # save error to database
2657                    /*$data['error_code'] = Configure::read('zeus.error.telecom_fail_withdrawal');
2658                    $this->_error_log_set($data);
2659                    echo "TelecomFailureWithdrawal";*/
2660
2661                } else {
2662                    $this->mySlack->channel = $this->slackChannel;
2663                    $this->mySlack->username = "Payment Withdrawal :";
2664                    $this->mySlack->text = "```";
2665                    $this->mySlack->text .= date("Y/m H:i") . "\n";
2666                    $this->mySlack->text .= "User " . $userData['User']['id'] . " succesfully withdrew from telecom!\n";
2667                    $this->mySlack->text .= "```";
2668
2669                    // send slack
2670                    $this->mySlack->sendSlack();
2671                }
2672            }
2673
2674            # check if formType = 5
2675            if ($formType == Configure::read('payment_credit_coin_purchase') && isset($ptPaymentParams['coinPurchasePoints'])) {
2676                
2677                $coinPurchasePoints = intVal($ptPaymentParams['coinPurchasePoints']);
2678                $coinData = $this->UsersPoint->SET_charge_overseas_menue($coinPurchasePoints, $currencyCode);
2679
2680                // NC-5007 add to the user's existing coin
2681                $pcZeusPay = array(
2682                    'userId' => $userData['User']['id'],
2683                    'point' => $coinData['num_of_coin'] - $coinData['bonus_coin'],
2684                    'kbn' => 7,
2685                    'kbnType' => 1, // add coin
2686                    'coinType' => 1, // purchase coin
2687                    'coinFailMessage' => Configure::read('coin.failed.buy_coin'),
2688                    'device' => isset($ptPaymentParams['device']) ? $ptPaymentParams['device'] : null
2689                );
2690
2691                $scZeusPay = array(
2692                    'userId' => $userData['User']['id'],
2693                    'point' => $coinData['bonus_coin'],
2694                    'kbn' => 7,
2695                    'kbnType' => 1, // add coin
2696                    'coinType' => 2, // service coin
2697                    'coinFailMessage' => Configure::read('coin.failed.buy_coin'),
2698                    'device' => isset($ptPaymentParams['device']) ? $ptPaymentParams['device'] : null
2699                );
2700
2701                $pointParams = [$pcZeusPay, $scZeusPay];
2702
2703                if ( $pointParams ) {
2704                    foreach($pointParams as $key => $val) {
2705                        if (!$this->UsersPoint->performPointTransaction($val)) {
2706                            $this->log(__METHOD__ . ' Failed to add user point. ' . json_encode($val) . ' -- ' . json_encode($data), $logFileName);
2707                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to add user point', $data, $val);
2708                            return ;
2709                        }
2710                    }
2711                }
2712            }
2713
2714            // check if family plan and a coin purchase form type 
2715            if (
2716                $familyId 
2717                && in_array($formType, array(
2718                        Configure::read('payment_credit_coin_purchase'), 
2719                        Configure::read('payment_credit_textbook_purchase')
2720                    )
2721                )
2722            ) {
2723                // change reference id to parent id
2724                $referenceId = isset($data['sendid']) ? $data['sendid'] : 0;
2725            
2726            //IF Native option or callan option join payment and family
2727            } elseif(
2728                (
2729                    isset($ptPaymentParams['nativeOptionJoin']) 
2730                    && $ptPaymentParams['nativeOptionJoin'] 
2731                    && $familyId
2732                    && $ptPaymentParams['formType'] == Configure::read('payment_native_option_join')
2733                ) 
2734                ||
2735                (
2736                    isset($ptPaymentParams['callanOptionJoin']) 
2737                    && $ptPaymentParams['callanOptionJoin'] 
2738                    && $familyId
2739                    && $ptPaymentParams['formType'] == Configure::read('payment_callan_option_join')
2740                )
2741            ) {
2742                // change reference id to parent id
2743                $referenceId = isset($data['sendid']) ? $data['sendid'] : 0;
2744            } else {
2745                $referenceId = $userId;
2746            }
2747            
2748            $paymentData = array(
2749                'user_id' => $userId,
2750                'amount' => $monthlyPayment,
2751                'status' => 1,
2752                'reference_id' => $referenceId,
2753                'payment_transaction_password' => $ptPassword,
2754                'card_company' => $card_company,
2755                'param1' => json_encode($data),
2756                'form_type' => $formType,
2757                'ordd' => $data["ordd"],
2758                'transaction_code' => $paymentHash,
2759                'currency_id' => Configure::read('default.settlement_currency_id'), // set currency id to jpy
2760                'currency_code' => $currencyCode,
2761                'payment_id' => $paymentPlanId,
2762                'price_id' => $priceId,
2763                'payment_type' => $paymentType
2764            );
2765            
2766            $discountOption = isset($ptPaymentParams['discountOption']) ? $ptPaymentParams['discountOption'] : [];
2767            
2768            if (!empty($discountOption)) {
2769                $paymentData['discount_option_price_id'] = $discountOption['discount_option_price_id'];
2770            }
2771            
2772            // NJ-47740
2773            $discountType = 'monthly';
2774            if ($formType == Configure::read('payment_native_option_join')) {
2775                $discountType = 'native';
2776            } else if ($formType == Configure::read('payment_callan_option_join')) {
2777                $discountType = 'callan';
2778            } else if ($formType == Configure::read('payment_credit_coin_purchase')) {
2779                $discountType = 'coin';
2780            }
2781            
2782            $getCouponDiscounDetail = PaymentTable::getCouponDiscountRequestDetail($ptPaymentParams, $discountType);
2783            $paymentData['discounted_amount'] = !empty($getCouponDiscounDetail['discounted_amount']) ? $getCouponDiscounDetail['discounted_amount'] : 0;
2784            $paymentData['coupon_request_id'] = !empty($getCouponDiscounDetail['coupon_request_id']) ? $getCouponDiscounDetail['coupon_request_id'] : null;
2785            
2786            $forceSettlementWithCoupon  = false;
2787            // if using coupon during force settlement
2788            if (
2789                !empty($ptPaymentParams['couponUseSettlement']) && 
2790                !empty($ptPaymentParams['couponUseSettlement']['useCouponAmount']) && 
2791                in_array($formType, Configure::read('allow_coupon.settlement_form_type'))
2792            ) {
2793                // apply coupon use discount
2794                $couponData = $ptPaymentParams['couponUseSettlement'];
2795                $couponData['nextChargeDate'] = date('Y-m-d');
2796                $couponData['request_result'] = true;
2797
2798                $result_coupon_use = $this->UsersCouponV1->performCouponUse($couponData);
2799                $result_coupon_use = !empty($result_coupon_use) ? json_decode($result_coupon_use,true) : array();
2800                
2801                if (empty($result_coupon_use)) {
2802                    $this->log(__METHOD__ . ' Failed to used coupons.' . json_encode($couponData), $logFileName);
2803                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to used coupons.', $couponData, array_merge($_POST, $_SERVER));
2804                    return false;
2805                }
2806                
2807                $paymentData['discounted_amount'] = $ptPaymentParams['couponUseSettlement']['useCouponAmount'];
2808                $paymentData['coupon_request_id'] = isset($result_coupon_use['cgrp_id']) ? $result_coupon_use['cgrp_id'] : null;
2809                
2810                $forceSettlementWithCoupon = true;
2811            }
2812            // NJ-47740 - end
2813            
2814            // NC-10009 95% OFF new year campaign
2815            // During NC-10009 campaign 
2816            // Temporary -> Premiuim Plan Paid
2817            // Create two payment data for card authentication and for premium plan paid payment
2818            $newYear95percentOffCampaign = false;
2819            if (
2820                (isset($ptPaymentParams['campaign95percentOff']) && $ptPaymentParams['campaign95percentOff'])
2821                && (isset($ptPaymentParams['userRegister']) && $ptPaymentParams['userRegister'])
2822            ) 
2823            {
2824                $newYear95percentOffCampaign = true;
2825                $paymentDataForCardAuthentication = $paymentData;
2826                $paymentDataForCardAuthentication['amount'] = 0;
2827                $paymentDataForCardAuthentication['form_type'] = Configure::read('payment_credit_authentication');
2828                $paymentDataForCardAuthentication['payment_id'] = Configure::read('payment_plans.free_trial');
2829                $paymentDataForCardAuthentication['price_id'] = 1;
2830                // create new for card authentication payment
2831                $this->Payment->clear();
2832                $this->Payment->create();
2833                $this->Payment->set($paymentDataForCardAuthentication);
2834                $this->Payment->save();
2835            }
2836
2837            //- check payment receivable with zero amount
2838            if (
2839                $formType == Configure::read('payment_credit_receivable') &&
2840                $monthlyPayment <= 0
2841            ) {
2842                //- skip saving
2843            } else {
2844                // create new payment
2845                $this->Payment->clear();
2846                $this->Payment->create();
2847                $this->Payment->set($paymentData);
2848                $savePaymentData = $this->Payment->save();
2849
2850                //update/add user`s settlement amount
2851                $this->User->updateUserPayments($paymentData);
2852                // check if payment was not saved
2853                if (!$this->Payment->save()) {
2854                    $this->log(__METHOD__ . ' Failed to save payment data. ' . json_encode($paymentData) . ' -- ' . json_encode($data), $logFileName);
2855                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data', $data, $paymentData);
2856                    
2857                    // if payment failed and has coupon grp id and its direct payment -> unconfirm coupon
2858                    if (
2859                        isset($paymentData['coupon_request_id']) && $paymentData['coupon_request_id'] &&
2860                        (
2861                            // the native or callan purchase with coupon use already has checker while processing the payment
2862                            // to ensure that payment errors are caught, place it here as well to make sure that the coupon is unconfirmed in case the page is refreshed while processing
2863                            in_array(
2864                                $formType, array(
2865                                    Configure::read('payment_native_option_join'),
2866                                    Configure::read('payment_callan_option_join'),
2867                                    Configure::read('payment_credit_coin_purchase')
2868                                )
2869                            ) ||
2870                            // force settlement with coupon
2871                            $forceSettlementWithCoupon
2872                        )
2873                    ) {
2874                        $couponKbn = Configure::read('coupon_kbn.coin_purchase'); // default
2875                        if ($formType == Configure::read('payment_native_option_join')) {
2876                            $couponKbn = Configure::read('coupon_kbn.native_option');
2877                        } else if ($formType == Configure::read('payment_callan_option_join')) {
2878                            $couponKbn = Configure::read('coupon_kbn.callan_option');
2879                        } else if ($forceSettlementWithCoupon) {
2880                            $couponKbn = Configure::read('coupon_kbn.monthly_settlement');
2881                        }
2882                        
2883                        $res_unconfirm = $this->UsersCouponV1->performCouponUnconfirm(array(
2884                            'grpId' => $paymentData['coupon_request_id'],
2885                            'userId' => $userId,
2886                            'kbn' => $couponKbn
2887                        ));
2888
2889                        if (empty($res_unconfirm)) {
2890                            $this->log(__METHOD__ . ' failed to perform coupon unconfirm.', $logFileName);
2891                        }
2892                    }
2893                    return ;
2894                }
2895                
2896                // update payment details
2897                $updatePaymentDetailParams = array(
2898                    'currencyCode' => $paymentData['currency_code'],
2899                    'formType' => $paymentData['form_type'],
2900                    'paymentType' => $paymentData['payment_type'],
2901                    'amount' => $paymentData['amount'],
2902                    'discounted_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0,
2903                    'familyId' => $familyId,
2904                    'cronDateRun' => $cronDateRun,
2905                    'priceId' => $paymentData['price_id'],
2906                    'paymentPlanId' => $paymentData['payment_id'],
2907                    'user_id' => $paymentData['user_id'],
2908                    'coupon_use_request_id' => isset($paymentData['coupon_request_id']) ? $paymentData['coupon_request_id'] : null,
2909                    'coupon_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0
2910                );
2911                
2912                if (!empty($discountOption)) {
2913                    $updatePaymentDetailParams['discount_option_price_id'] = $discountOption['discount_option_price_id'];
2914                    $updatePaymentDetailParams['discount_option_amount'] = $discountOption['amount'];
2915                }
2916                $updatePaymentDetail = array(
2917                    'id' => $ptId,
2918                    'fields' => array(
2919                        'payment_details' => $updatePaymentDetailParams
2920                    )
2921                );
2922
2923                if (!$this->PaymentTransaction->updateWPPaymentTransaction($updatePaymentDetail)) {
2924                    $this->log(__METHOD__ . ' Failed to update payment details. ' . json_encode($updatePaymentDetail), $logFileName);
2925                }
2926
2927                // set payment_id
2928                $paymentSaveID = $this->Payment->id;
2929                
2930                // NJ-47740
2931                if (!empty($paymentData['coupon_request_id']) && $paymentData['discounted_amount'] > 0) {
2932                    // confirm coupon use request for discount
2933                    $requestCouponConfirmData = array(
2934                        'grpId' => $paymentData['coupon_request_id'],
2935                        'paymentId' => $paymentSaveID
2936                    );
2937                    $result_confirm = $this->UsersCouponV1->performCouponConfirm($requestCouponConfirmData);
2938                    
2939                    if (!$result_confirm) {
2940                        $this->log(__METHOD__ . ' Failed to confirm coupon use request. ' . json_encode($requestCouponConfirmData) . ' -- ' . json_encode($data), $logFileName);
2941                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to confirm coupon use request', $data, $requestCouponConfirmData);
2942                        return ;
2943                    }
2944                }
2945                // NJ-47740 end
2946                
2947                // NJ-35237
2948                if (!empty($ptPaymentParams['rewardedPoints'])) {
2949                    $rewaredPointParams['ContinuationRewardPoint'] = $ptPaymentParams['rewardedPoints'];
2950                    // save reward point
2951                    if (!$this->ContinuationRewardPoint->saveRewardPoint($rewaredPointParams)) {
2952                        $this->log(__METHOD__ . ' Failed to save reward point. --> ' . json_encode($rewaredPointParams), $this->logFileName);
2953                    }
2954                }
2955                // NJ-35237 end
2956            }
2957
2958            if (
2959                $formType != Configure::read('payment_credit_textbook_purchase') &&
2960                $formType != Configure::read('payment_credit_receivable') &&
2961                $formType != Configure::read('payment_credit_appreciation_receivable') &&
2962                $formType != Configure::read('payment_credit_coin_purchase') &&
2963                $formType != Configure::read('payment_native_option_join') &&
2964                $formType != Configure::read('payment_native_option_monthly_payment') &&
2965                $formType != Configure::read('payment_callan_option_join') &&
2966                $formType != Configure::read('payment_callan_option_monthly_payment') &&
2967                $formType != Configure::read('payment_halfway_termination_of_annual_discount_option') &&
2968                $formType != Configure::read('payment_study_abroad')
2969            ) {
2970
2971                # user array to be saved
2972                $saveUserArr = array(
2973                    'User' => array(
2974                        'status' => 1,
2975                        'modified' => date('YmdHis'),
2976                        'fail_flg' => 0,
2977                        'charge_flg' => 1,
2978                        'counseling_attended_flg' => 0,
2979                        'card_company' => $card_company,
2980                        'hash16' => $userData['User']['id'],
2981                        'last_charge_date' => date('YmdHis'),
2982                        'card_number' => $data['cardnumber'], // NC-3914
2983                        'card_brand' => $data['cardbrand'], // NC-3914
2984                        'payment_plan_id' => $paymentPlanId,
2985                        'price_id' => $priceId,
2986                        'corporate_id' => null,
2987                        'corporate_type' => null,
2988                        'paypal_billing_agreement_id' => null,
2989                        'paypal_payer_id' => null,
2990                        'is_new_premium_flg' => 0,
2991                        'double_check_flg' => 1
2992                    )
2993                );
2994
2995                // if not empty card expiration date
2996                if (isset($ptPaymentParams['cardExpirationDate'])) {
2997                    $saveUserArr['User']['card_expiration_date'] = $ptPaymentParams['cardExpirationDate'];
2998                }
2999
3000                // set child card expiration date same as parent
3001                if (isset($ptPaymentParams['family_data']['applyPlan']['card_expiration_date'])) {
3002                    $saveUserArr['User']['card_expiration_date'] = $ptPaymentParams['family_data']['applyPlan']['card_expiration_date'];
3003                }
3004
3005                // ----
3006                # check payment if credit authentication
3007                if (
3008                    in_array(
3009                        $formType, 
3010                        [
3011                            Configure::read('payment_lite_credit_free'),
3012                            Configure::read('payment_credit_authentication'),
3013                            Configure::read('payment_credit_family_free'),
3014                            Configure::read('payment_credit_chocotto_free')
3015                        ]
3016                    )
3017                ) {
3018                    $saveUserArr['User']['first_charge_date'] = date('Y-m-d H:i:s');
3019                    $saveUserArr['User']['platform'] = $platform;
3020                // if complimentary plan unsubscribe and resubscribe
3021                } elseif (isset($ptPaymentParams['updateFirstChargeDate']) || $newYear95percentOffCampaign) {
3022                    $saveUserArr['User']['first_charge_date'] = date('Y-m-d H:i:s');
3023                }
3024
3025                // if bonus coin flg is set
3026                if (isset($ptPaymentParams['bonusCoinFlg'])) {
3027                    $saveUserArr['User']['bonus_coin_flg'] = $ptPaymentParams['bonusCoinFlg'];
3028                }
3029                //NJ-7874 if appreciation flag and amount is set
3030                if (isset($ptPaymentParams['family_data']['applyPlan']['tip_max_amount']) && $ptPaymentParams['family_data']['applyPlan']['tip_max_amount']) {
3031                    $tipAmount = $ptPaymentParams['family_data']['applyPlan']['tip_max_amount'];
3032                }
3033
3034                if (isset($ptPaymentParams['family_data']['applyPlan']['allow_appreciation_flg']) && $ptPaymentParams['family_data']['applyPlan']['allow_appreciation_flg'] && $tipAmount) {
3035                    $appreciationFlg = 1;
3036                }
3037                
3038                # check if subscription payment
3039                if (
3040                    $formType == Configure::read('payment_credit_force_charge') ||
3041                    $formType == Configure::read('payment_credit_retry') ||
3042                    $formType == Configure::read('payment_credit_monthly_payment') ||
3043                    $formType == Configure::read('payment_credit_family_monthly_payment') ||
3044                    $formType == Configure::read('payment_credit_family_free') || 
3045                    $formType == Configure::read('payment_lite_credit_monthly_payment') || 
3046                    $formType == Configure::read('payment_lite_credit_paid') ||
3047                    $formType == Configure::read('payment_credit_chocotto_monthly_payment') ||
3048                    $formType == Configure::read('payment_credit_chocotto_retry') ||
3049                    $formType == Configure::read('payment_credit_chocotto_force_charge')
3050                ) {
3051                    # get and set next charge date
3052                    $nextChargeDate = $this->User->getNextChargeDate();
3053                    $saveUserArr['User']['next_charge_date'] = $nextChargeDate;
3054                    $saveUserArr['User']['double_check_flg'] = 1;
3055                    $saveUserArr['User']['expired_card_flg'] = 0; // NC-3902
3056
3057                    // NJ-1562 - appreciation on
3058                    if( $paymentPlanId && in_array( $paymentPlanId, Configure::read('appreciation.payment_plan_id') ) ) {
3059                        //$saveUserArr['User']['allow_appreciation_flg'] = 1; // on
3060                        if (in_array($paymentPlanId,Configure::read('appreciation.can_coin_purchase_check')) ) {
3061                            //set the appreciation flg to be set
3062                            $saveUserArr['User']['allow_appreciation_flg'] = $appreciationFlg;
3063                            $saveUserArr['User']['show_appreciation_flg'] = $appreciationFlg;
3064                            $saveUserArr['User']['tip_max_amount'] = $tipAmount;
3065                        }else{
3066                            $saveUserArr['User']['allow_appreciation_flg'] = 1; // on
3067
3068                            if (
3069                                $formType == Configure::read('payment_credit_force_charge') || 
3070                                $formType == Configure::read('payment_credit_retry') || 
3071                                $formType == Configure::read('payment_lite_credit_paid')
3072                            ) {
3073                                $showAppreciationFlg = 0;//set  the default show appreciation flg
3074
3075                                //NJ-7548 : check user birthday and age ; $userData['User']['birthday']
3076                                $userAge = UserTable::getStudentAge($userData['User']['birthday']);
3077                                $userAge = $userAge ? (int) $userAge : null;
3078
3079                                //change the show appreciation flg if no birthday set or 18 and above
3080                                if (!$userAge || $userAge >= 18) {
3081                                    $showAppreciationFlg = 1;
3082                                }
3083
3084                                $saveUserArr['User']['show_appreciation_flg'] = $showAppreciationFlg; // on
3085                            }
3086                        }
3087                    }
3088                    
3089                    if ($formType == Configure::read('payment_credit_family_free')) {
3090                        $nextChargeDate = $this->User->getFirstNextChargeDate();
3091                        $saveUserArr['User']['next_charge_date'] = $nextChargeDate;
3092                    }
3093
3094                    # give points to user join the campaign who retry payment
3095                    if ($formType == Configure::read('payment_credit_retry') && !$isLitePlanUser) {
3096                        $this->ContinuationCampaign->givePointsRetrySuccess(array(
3097                            'user_ids' => array($userData['User']['id'])
3098                        ));
3099                    }
3100
3101                    # give points if user join campaign and success payment
3102                    if ($formType == Configure::read('payment_credit_monthly_payment')) {
3103                        $this->ContinuationCampaign->givePoints(array(
3104                            'user_id' => $userData['User']['id']
3105                        )); 
3106                    }
3107
3108                    # give coins if temporary/new user is changed/added to family plan
3109                    if ($formType == Configure::read('payment_credit_family_free') && $userData['User']['status'] == 0) {
3110                        // NJ-4746: defult bonus point
3111                        $defaultBC = ClassRegistry::init("DefaultCoinRegistration")->defaultCoins();
3112                        $bonusPoints = (($defaultBC > 0) ? $defaultBC : Configure::read("credit.bonus_coin_authentication"));
3113
3114                        // camapaign master triiger 1
3115                        $campaignMaster = ClassRegistry::init('CampaignMaster')->bonusTrigger(['userId' => $userData['User']['id'], 'triggerNo' => 1]);
3116                        if (!$campaignMaster['bonusCoins'] && !$campaignMaster['bonusCoupons']) {
3117                            # add to the user's existing coin
3118                            $pointParams = array(
3119                                'userId' => $userData['User']['id'],
3120                                'point' => $bonusPoints,
3121                                'kbn' => Configure::read("point_history.bonus"),
3122                                'kbnType' => 1, // add coin
3123                                'coinType' => 2, // service coin
3124                                'coinFailMessage' => Configure::read('coin.failed.campaign')
3125                            );
3126                            if (!$this->UsersPoint->performPointTransaction($pointParams)) {
3127                                $this->log(__METHOD__ . ' Failed add point to user. ' . json_encode($pointParams) . ' -- ' . json_encode($data), $logFileName);
3128                                $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed add point to user', $data, $pointParams);
3129                                return ;
3130                            }
3131                        }
3132                    }
3133
3134                    # give points if user join retry payment lite 
3135                    if ($formType == Configure::read('payment_credit_retry') && $isLitePlanUser) {
3136                        $this->liteUserAddCoinRewardForReenroll(array('id' => $userData['User']['id']));
3137                    }
3138
3139                } elseif (
3140                    $formType ==  Configure::read('payment_credit_authentication') || 
3141                    $formType == Configure::read('payment_lite_credit_free') ||
3142                    $formType == Configure::read('payment_credit_chocotto_free')
3143                ) {
3144                    // Normal user
3145                    $nextChargeDate = $this->User->getFirstNextChargeDate();
3146                    $saveUserArr['User']['next_charge_date'] = $nextChargeDate;
3147
3148                    // NJ-1562 - appreciation on
3149                    if( $paymentPlanId && in_array( $paymentPlanId, Configure::read('appreciation.payment_plan_id') ) ) {
3150                        //$saveUserArr['User']['allow_appreciation_flg'] = 1; // on
3151                        if (in_array($paymentPlanId,Configure::read('appreciation.can_coin_purchase_check')) ) {
3152                            //set the appreciation flg to be set
3153                            $saveUserArr['User']['allow_appreciation_flg'] = $appreciationFlg;
3154                            $saveUserArr['User']['show_appreciation_flg'] = $appreciationFlg;
3155                            $saveUserArr['User']['tip_max_amount'] = $tipAmount;
3156                        }else{
3157                            $saveUserArr['User']['allow_appreciation_flg'] = 1; // on
3158
3159                            $showAppreciationFlg = 0;
3160
3161                            //NJ:7548: fetch the age of the user
3162                            $uAge = UserTable::getStudentAge($userData['User']['birthday']);
3163                            $uAge = $uAge ? (int) $uAge : null;
3164
3165                            //change the show appreciation flg if no birthday set or 18 and above
3166                            if (!$uAge || $uAge >= 18) {
3167                                $showAppreciationFlg = 1;
3168                            }
3169
3170                            //set the save user array 
3171                            $saveUserArr['User']['show_appreciation_flg'] = $showAppreciationFlg; // set
3172                        }
3173                    }
3174                }
3175
3176                #NJ-7548 : if credit card changed to zeus 
3177                if (
3178                    $formType == Configure::read('payment_credit_change') && 
3179                    $paymentPlanId && in_array( $paymentPlanId, Configure::read('appreciation.payment_plan_id') )
3180                ) {
3181                    
3182                    if (in_array($paymentPlanId,Configure::read('appreciation.can_coin_purchase_check')) ) {
3183                        //set the appreciation flg to be set
3184                        $saveUserArr['User']['allow_appreciation_flg'] = $appreciationFlg;
3185                        $saveUserArr['User']['show_appreciation_flg'] = $appreciationFlg;
3186                        $saveUserArr['User']['tip_max_amount'] = $tipAmount;
3187                    }else{
3188                        $saveUserArr['User']['allow_appreciation_flg'] = 1; // on
3189
3190                        $showAppreciationFlg = 0;//set  the default show appreciation flg
3191
3192                        //NJ-7548 : check user birthday and age ; $userData['User']['birthday']
3193                        $userAge = UserTable::getStudentAge($userData['User']['birthday']);
3194                        $userAge = $userAge ? (int) $userAge : null;
3195
3196                        //change the show appreciation flg if no birthday set or 18 and above
3197                        if (!$userAge || $userAge >= 18) {
3198                            $showAppreciationFlg = 1;
3199                        }
3200
3201                        $saveUserArr['User']['show_appreciation_flg'] = $showAppreciationFlg; // on
3202                    }
3203                }
3204
3205
3206                // if credit card change from android or apple
3207                if (
3208                    in_array($formType, array(Configure::read('payment_credit_change'), Configure::read('payment_credit_authentication'))) &&
3209                    in_array($userData['User']['card_company'], array(Configure::read('card_company.apple'), Configure::read('card_company.google')))
3210                ) {
3211                    // NC-5007 add to user's existing number of coins
3212                    $pointParams = array(
3213                        'userId' => $userData['User']['id'],
3214                        'point' => 500,
3215                        'kbn' => 6,
3216                        'kbnType' => 1, // add coin
3217                        'coinType' => 2, // service coin
3218                        'coinFailMessage' => Configure::read('coin.failed.campaign')
3219                    );
3220                    if (!$this->UsersPoint->performPointTransaction($pointParams)) {
3221                        $this->log(__METHOD__ . ' Failed add point to user. ' . json_encode($pointParams) . ' -- ' . json_encode($data), $logFileName);
3222                        $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed add point to user', $data, $pointParams);
3223                        return ;
3224                    }
3225
3226                    // log for debugging
3227                    $this->log("[ZEUSPAY] switching user from android/ios to zeus -> " . json_encode($data), "debug");
3228                }
3229
3230                $discountOption = isset($ptPaymentParams['discountOption']) ? $ptPaymentParams['discountOption'] : [];
3231                $zeroStudentDiscount = false;
3232
3233                // set premium_coin_purchase_flg to 0 and set first charge date
3234                if (
3235                    $discountOption &&
3236                    $formType == Configure::read('payment_lite_credit_monthly_payment') && 
3237                    isset($ptPaymentParams['userRegister']) &&
3238                    $ptPaymentParams['userRegister']
3239                ) {
3240                    $saveUserArr['User']['premium_coin_purchase_flg'] = 0;
3241                    $saveUserArr['User']['first_charge_date'] = date('Y-m-d H:i:s');
3242                }
3243
3244                # update the user information
3245                $this->User->validate = array();
3246                if (!$read = $this->User->read(null, $userData['User']['id'])) {
3247                    $this->log(__METHOD__ . ' User id does not exist. ' . json_encode($userData) . ' -- ' . json_encode($data), $logFileName);
3248                    $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'User id does not exist', $data, $userData);
3249                    return ;
3250                }
3251                $currency_before = $userData['User']['currency_code'];
3252                $plan_before = $userData['User']['payment_plan_id'];
3253
3254                $famRegist = false;
3255                // NC-4673: update family parent_id, memo and monthly_payment
3256
3257
3258                if (
3259                    in_array($formType, Configure::read('family_plan_form_types'))
3260                ) {
3261                    // if parent_id is empty
3262                    if (empty($read['User']['parent_id'])) {
3263                        $saveUserArr['User']['parent_id'] = $data['sendid'];
3264                        $saveUserArr['User']['memo'] = date('Y/m/d H:i:s')." Family plan[User]: family registration \n".$read['User']['memo'];
3265                        $famRegist = true;
3266
3267                
3268                        if (empty($read['User']['currency_code'])) {
3269                            $saveUserArr['User']['currency_code'] = $currencyCode;
3270                        }
3271                    }
3272                }
3273
3274                // - NJ-18780 : add next charge date for upgrade and downgrade plan
3275                if (
3276                    (
3277                        $formType == Configure::read('payment_lite_plan_downgrade') || 
3278                        $formType == Configure::read('payment_lite_plan_upgrade')
3279                    )
3280                    && (isset($ptPaymentParams['changePlanChargeFlg']) && $ptPaymentParams['changePlanChargeFlg'])
3281                ) {
3282                    $nextChargeDate = $this->User->getNextChargeDate();
3283                    $saveUserArr['User']['next_charge_date'] = $nextChargeDate;
3284                }
3285
3286                //- chocotto credit auth remove the campaign code
3287                if ($formType == Configure::read('payment_credit_chocotto_free')) {
3288                    $saveUserArr['User']['campaign_id'] = NULL;
3289                }
3290
3291
3292                // campaign master trigger 2
3293                if (
3294                    strtoupper($data['result']) == 'OK' &&
3295                    $formType == Configure::read('payment_credit_monthly_payment') && 
3296                    $userData['User']['payment_plan_id'] == Configure::read('payment_plans.free_trial')
3297                ) {
3298                    UsersPointTable::giveBonusCoins(['userId' => $userId, 'triggerNo' => 2]);
3299                }
3300                // - NJ-36141: whenever status changed, reset Chocotto Daily Lesson Time
3301                $this->UsersDetail->chocottoCampUserDetails($userData['User']['id'], true);
3302                $this->User->set($saveUserArr);
3303                if (!$this->User->save()) {
3304                    $this->log(__METHOD__ . ' Failed update user data. ' . json_encode($saveUserArr) . ' -- ' . json_encode($data), $logFileName);
3305                    $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed update user data', $data, $saveUserArr);
3306                    return ;
3307                }
3308
3309                // check if payment plan upgrade
3310                if ($formType == Configure::read('payment_lite_plan_upgrade')) {
3311                    // get user zero student discount term
3312                    $discountOptionTermData = $this->UserDiscountOptionsTerm->getTerm([
3313                        'user_id' =>  $userId,
3314                        'discount_option_id' => Configure::read('discount_option.zero_student.plan_id'),
3315                        'status' => 1
3316                    ]);
3317
3318                    // stop zero student discount
3319                    if ($discountOptionTermData) {
3320                        // open tunnel
3321                        myTools::initializeApiTunnel(['DiscountOptionController']);
3322
3323                        // initialize controller
3324                        $doc = new DiscountOptionController();
3325
3326                        $docParams = [
3327                            'discountOptionId' => $discountOptionTermData['discount_option_id'],
3328                            'discountOptionPriceId' => $discountOptionTermData['discount_option_price_id'],
3329                            'termId' => $discountOptionTermData['discount_option_term_id'],
3330                            'cancellationFee' => 0,
3331                            'cancellationType' => Configure::read('discount_option.dosh_type.plan_change'),
3332                            'userData' => $userData['User'],
3333                            'fromController' => $this->request->params['controller'],
3334                            'fromAction' => $this->request->params['action'],
3335                            'doshStatus' => Configure::read('discount_option.dosh_status.midterm_cancellation')
3336                        ];
3337
3338                        // set data
3339                        $doc->params = $docParams;
3340
3341                        if (!$doc->stopDiscountOption()) {
3342                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to stop discount option. ', $docParams);
3343                            return ;
3344                        }
3345                    }
3346                }
3347
3348                // if user plan has discount option
3349                if ($discountOption) {
3350                    $contractStart = $formType != Configure::read('payment_credit_authentication') ? date('Y-m-d 00:00:00') : (isset($nextChargeDate) ? $nextChargeDate : $this->User->getFirstNextChargeDate());
3351                    if (
3352                        (
3353                            $discountOption['discount_option_id'] == Configure::read('discount_option.zero_student.plan_id') &&
3354                            $formType == Configure::read('payment_lite_credit_monthly_payment') && 
3355                            isset($ptPaymentParams['userRegister']) &&
3356                            $ptPaymentParams['userRegister']
3357                        ) ||
3358                        in_array(
3359                            $formType,
3360                            [
3361                                Configure::read('payment_credit_authentication'),
3362                                Configure::read('payment_credit_force_charge'),
3363                                Configure::read('payment_lite_plan_upgrade')
3364                            ]
3365                        )
3366                    ) {
3367                        // set amount to 0 if card auth
3368                        if ($formType == Configure::read('payment_credit_authentication')) {
3369                            $discountOption['amount'] = 0;
3370                        }
3371
3372                        // set data for user discount option term
3373                        $udotData = [
3374                            'userId' => $userId,
3375                            'discountOptionId' => $discountOption['discount_option_id'],
3376                            'discountOptionPriceId' => $discountOption['discount_option_price_id'],
3377                            'contractStart' => $contractStart,
3378                            'logFileName' => $logFileName,
3379                            'paymentId' => $paymentSaveID,
3380                            'discountAmount' => $discountOption['amount'],
3381                            'doshEvent' => isset($discountOption['dosh_event']) ? $discountOption['dosh_event'] : null,
3382                            'currencyCode' => $currencyCode,
3383                            'doshStatus' => isset($discountOption['dosh_status']) ? $discountOption['dosh_status'] : null,
3384                            'formType' => $formType,
3385                            'userRegister' => isset($ptPaymentParams['userRegister']) ? true : false
3386                        ];
3387
3388                        if (isset($discountOption['dosh_type'])) {
3389                            $udotData['doshType'] = $discountOption['dosh_type'];
3390                        }
3391
3392                        if (
3393                            $discountOption['discount_option_id'] == Configure::read('discount_option.zero_student.plan_id') &&
3394                            $formType == Configure::read('payment_lite_credit_monthly_payment')
3395                        ) {
3396                            $zeroStudentDiscount = true;
3397                        }
3398
3399                        // create user discount option term
3400                        if (!$this->UserDiscountOptionsTerm->createTerm($udotData)) {
3401                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to create user discount option term. ', $udotData);
3402                            return ;
3403                        }
3404
3405                        // check if has uploaded data for zero student document(s)
3406                        if (isset($discountOption['application_form_app_image_url'])) {
3407                            $applicationData = [
3408                                'user_id' => $userId,
3409                                'image_url' => $discountOption['application_form_app_image_url']
3410                            ];
3411            
3412                            // save document url
3413                            if (!$this->StudentDiscountApplicationForm->saveApplicationForm($applicationData)) {
3414                                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save zero student application form. ', $applicationData);
3415                                return ;
3416                            }
3417
3418                            $udData = [
3419                                'user_id' => $userId,
3420                                'individual_card_fail_flg'    => 0,
3421                                'show_zero_student_discount_option_flg' => 1
3422                            ];
3423
3424                            $this->UsersDetail->clear();
3425                            $this->UsersDetail->set($udData);
3426                            $this->UsersDetail->validate = [];
3427                            if (!$this->UsersDetail->save()) {
3428                                $this->log(__METHOD__ . ' Failed insert users detail data. ' . json_encode($udData) . ' -- ' . json_encode($data), $logFileName);
3429                                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to insert users detail data. ', $udData);
3430                                return ;
3431                            }
3432
3433                            $slackParams = [
3434                                'userId' => $userId,
3435                                'nickname' => $userData['User']['nickname'],
3436                                'nextChargeDate' => $this->User->getNextChargeDate(),
3437                                'applicationCnt' => 1,
3438                                'appFormUrl' => $discountOption['application_form_app_image_url']
3439                            ];
3440
3441                            // send slack
3442                            StudentDiscountApplicationFormTable::sendSlackStudentDiscountInfo($slackParams);
3443                        }
3444                    } elseif (in_array($formType, [Configure::read('payment_credit_monthly_payment'), Configure::read('payment_credit_retry')])) {
3445                        $discountOption += [
3446                            'contract_start' => $contractStart,
3447                            'currency_code' => $currencyCode,
3448                            'payment_id' => $paymentSaveID,
3449                            'dosh_settlement_status' => 1, // success
3450                            'form_type' => $formType
3451                        ];
3452
3453                        if (!$this->UserDiscountOptionsTerm->processMonthlyDiscountOption($discountOption)) {
3454                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to process monthly discount option. ', $discountOption);
3455                            return ;
3456                        }
3457                    }
3458
3459                    if (
3460                        (
3461                            in_array(
3462                                $formType,
3463                                [
3464                                    Configure::read('payment_credit_authentication'),
3465                                    Configure::read('payment_credit_force_charge'),
3466                                    Configure::read('payment_lite_plan_upgrade')
3467                                ]
3468                            ) ||
3469                            (
3470                                $discountOption['discount_option_id'] == Configure::read('discount_option.zero_student.plan_id') &&
3471                                $formType == Configure::read('payment_lite_credit_monthly_payment') && 
3472                                isset($ptPaymentParams['userRegister']) &&
3473                                $ptPaymentParams['userRegister']
3474                            )
3475                        ) &&
3476                        isset($discountOption['option_after_name']) &&
3477                        isset($discountOption['option_type'])
3478                    ) {
3479                        $adoLogParams = [
3480                            'user_id' => $userId,
3481                            'platform' => $platform,
3482                            'status' => 1, // subscribe
3483                            'controller_name' => $this->request->params['controller'],
3484                            'action_name' => $this->request->params['action'],
3485                            'user_type' => 0, // normal user
3486                            'option_before' => '',
3487                            'option_after' => 1,
3488                            'option_before_name' => isset($discountOption['option_before_name']) ? $discountOption['option_before_name'] : '',
3489                            'option_after_name' => $discountOption['option_after_name'],
3490                            'option_type' => $discountOption['option_type'],
3491                            'payment_plan_id' => $paymentPlanId
3492                        ];
3493
3494                        if (!$this->UserOptionChangeLog->saveOptionChangeLog($adoLogParams)) {
3495                            $this->log(__METHOD__ . ' Failed to update option change. ' . json_encode($adoLogParams), $logFileName);
3496                            $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'Failed to update user data', $adoLogParams);
3497                            return ;
3498                        }
3499                    }
3500                }
3501
3502                # NJ-27262 chocotto plan charge or 
3503                if (in_array(
3504                    $formType, [
3505                        Configure::read('payment_credit_chocotto_monthly_payment'),
3506                        Configure::read('payment_credit_chocotto_retry')
3507                    ]
3508                )) {
3509                    //- confiscate lite points
3510                    UserTable::changePlanProcess(['user_id' => $userId]);
3511
3512                    //- update users if has options
3513                    if (
3514                        !empty($userData['User']['native_option']) ||
3515                        !empty($userData['User']['callan_option'])
3516                    ) {
3517                        $_userUpdate = array('id' => $userData['User']['id']);
3518
3519                        //- native options
3520                        if (!empty($userData['User']['native_option'])) {
3521                            $_userUpdate['native_option'] = 0;
3522                            $_userUpdate['native_option_cancellation_time'] = date('Y-m-d H:i:s');
3523                        }
3524
3525                        //- callan options
3526                        if (!empty($userData['User']['callan_option'])
3527                        ) {
3528                            $_userUpdate['callan_option'] = 0;
3529                            $_userUpdate['callan_option_cancellation_time'] = date('Y-m-d H:i:s');
3530                        }
3531                        $this->User->set($_userUpdate);
3532                        if (!$this->User->save()) {
3533                            $this->log(__METHOD__ . ' Failed to update user data. ' . json_encode($_userUpdate), $logFileName);
3534                            $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed to update user data', $_userUpdate);
3535                        }
3536                    }
3537                }
3538
3539                # NJ-18780 : changed plan to liteplan
3540                if (
3541                    $formType == Configure::read('payment_lite_plan_downgrade') || 
3542                    $formType == Configure::read('payment_lite_plan_upgrade')
3543                ) {
3544                    $this->User->openDBReplica();
3545                    $_currentUser = $this->User->find('first', array(
3546                        'fields' => array('User.parent_id', 'User.currency_code', 'User.payment_plan_id','User.memo','User.native_option','User.callan_option','next_charge_date'),
3547                        'conditions' => array('User.id' => $userData['User']['id']),
3548                        'recursive' => -1
3549                    ));
3550                        $this->User->closeDBReplica();
3551
3552                    $_memoCoins = 'SC and PC';
3553                    $_updateMemo = '';
3554                    $litenativeOptionBefore = $litenativeOptionAfter = $_currentUser['User']['native_option'];
3555                       $litecallanOptionBefore = $litecallanOptionAfter = $_currentUser['User']['callan_option'];
3556                       $isliteNativeOptionChange = $isliteCallanOptionChange = false;
3557
3558                       $liteUserUpdateArr = array();
3559                       $_dateNow = date("Y-m-d H:i:s");
3560
3561                    // - turn off native option if it is on
3562                    if ((int) $litenativeOptionBefore == 1) {
3563                        $liteUserUpdateArr['native_option'] = 0; // turn off
3564                        $liteUserUpdateArr['native_option_cancellation_time'] = $dateNow;
3565                        $litenativeOptionAfter = 0;
3566                        $isliteNativeOptionChange = true;
3567
3568                        // set memo
3569                        $_updateMemo = $_updateMemo. "\n{$_dateNow} \nChanged by due Selected Light Plan / Native Unlimited option OFF";
3570                    }
3571
3572                    // - turn off callan option if it is on
3573                    if ((int) $litecallanOptionBefore == 1) {
3574                        $liteUserUpdateArr['callan_option'] = 0; // turn off
3575                        $liteUserUpdateArr['callan_option_cancellation_time'] = $dateNow;
3576                        $litecallanOptionAfter = 0;
3577                        $isliteCallanOptionChange = true;
3578
3579                        $_updateMemo = $_updateMemo. "\n{$_dateNow} \nChanged by due Selected Light Plan / Callan Unlimited option OFF";
3580                    }
3581
3582                    // - changing to lite plan
3583                    if ($formType == Configure::read('payment_lite_plan_downgrade')) {
3584                    
3585                        // - confiscate all mc coins
3586                        $_monthlyPoints = $this->UsersPoint->getCurrentUserMCPoint($userData['User']['id']); 
3587                        $_memoCoins = "MC";
3588
3589                        if ((int) $_monthlyPoints > 0) {
3590                            $confiscateParams = array(
3591                                'userId' => $userData['User']['id'],
3592                                'point' => $_monthlyPoints,
3593                                'kbn' => 18, 
3594                                'coinType' => 3
3595                            );
3596
3597
3598                            // rollback if confiscating points failed
3599                            if (!$confiscateCoinFlg = $this->UsersPoint->confiscateUserLitePoints($confiscateParams)) {
3600                                $this->log(__METHOD__ . ' Failed to confiscate points. --> ' . json_encode($confiscateParams) . ' -- ' . json_encode($data), $logFileName);
3601                                        
3602                                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userData['User']['id'], 'Failed to confiscate points.', $userData);
3603                                return ;
3604                            }
3605
3606                            $_updateMemo = $_updateMemo . "\n {$_dateNow} (Previous Coins ({$_memoCoins})【Confiscated】 : {$_monthlyPoints}. )";
3607                        }
3608
3609                        $doneConfiscatePoints = ClassRegistry::init('UsersPointHistory')->confiscateUserLitePointsCoinBox($userData['User']['id']);
3610
3611                        $nextChargeDateLite = $this->User->getNextChargeDate();
3612
3613                        // - give lite bonus coins
3614                        $_pointParams = array(
3615                            'userId' => $userData['User']['id'],
3616                            'point' => Configure::read('lite_plan_monthly_coin'),
3617                            'kbn' => Configure::read('lite_plan_bonus_kbn'), // 
3618                            'kbnType' => 1, // add coin
3619                            'coinType' => 3, // mc coin
3620                            'dateExpiration' => $nextChargeDateLite,
3621                            'coinFailMessage' => Configure::read('coin.failed.membership')
3622                        );
3623
3624                        // rollback if adding  points failed
3625                        if (!$_addCoinsFlg = $this->UsersPoint->performPointTransaction($_pointParams)) {
3626                            $this->log(__METHOD__ . ' Failed to give points. --> ' . json_encode($confiscateParams) . ' -- ' . json_encode($data), $logFileName);
3627                                    
3628                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to give points.', $data);
3629                            return ;
3630                        }
3631
3632                        $_coins = Configure::read('lite_plan_monthly_coin');
3633                        $updateMemo = $updateMemo . "\n {$_dateNow} | Light Plan Bonus Coins (MC): {$_coins}";
3634                    }
3635
3636                    // - changing from premium to lite plan
3637                    if ($formType == Configure::read('payment_lite_plan_upgrade')) {
3638                        // - confiscate all held coins
3639                        $_monthlyPoints = $this->UsersPoint->getCurrentUserMCPoint($userData['User']['id']); //  mc coins
3640
3641                        $_memoCoins = "MC";
3642
3643                        if ((int) $_monthlyPoints > 0) {
3644                            $confiscateParams = array(
3645                                'userId' => $userData['User']['id'],
3646                                'point' => $_monthlyPoints,
3647                                'kbn' => 18, 
3648                                'coinType' => 3
3649                            );
3650
3651
3652                            // rollback if confiscating points failed
3653                            if (!$confiscateCoinFlg = $this->UsersPoint->confiscateUserLitePoints($confiscateParams)) {
3654                                $this->log(__METHOD__ . ' Failed to confiscate points. --> ' . json_encode($confiscateParams) . ' -- ' . json_encode($data), $logFileName);
3655                                        
3656                                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userData['User']['id'], 'Failed to confiscate points.', $userData);
3657                                return ;
3658                            }
3659
3660                            $_updateMemo = $_updateMemo . "\n {$_dateNow} (Previous Coins ({$_memoCoins})【Confiscated】 : {$_monthlyPoints}. )";
3661                        }
3662
3663                        $_doneConfiscatePoints = ClassRegistry::init('UsersPointHistory')->confiscateUserLitePointsCoinBox($userData['User']['id']);
3664                    }
3665
3666                    #update the user information memo
3667                    if (empty($_updateMemo)) {
3668
3669                        $_updateMemo = $_updateMemo . "\n" . $_currentUser['User']['memo'];
3670                     
3671                        $_userUpdate = array(
3672                            'id' => $userData['User']['id'],
3673                            'memo' => $_updateMemo
3674                        );
3675
3676                        $this->User->set($_userUpdate);
3677                        if (!$this->User->save()) {
3678                            $this->log(__METHOD__ . ' Failed to update user data. ' . json_encode($_userUpdate), $logFileName);
3679                            $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed to update user data', $_userUpdate);
3680                            return ;
3681                        }
3682                    }
3683
3684                    // - update the user information
3685                    if ($liteUserUpdateArr) {
3686                        $liteUserUpdateArr['id'] = $userData['User']['id'];
3687
3688                        // - set user 
3689                        $this->User->set($liteUserUpdateArr);
3690
3691                        if (!$this->User->save()) {
3692                            $this->log(__METHOD__ . ' Failed to update user data. ' . json_encode($liteUserUpdateArr), $logFileName);
3693                            $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed to update user data', $_userUpdate);
3694                            return ;
3695                        }
3696                    }
3697
3698                    # add log if there is change on native option
3699                    if ($isliteNativeOptionChange) {
3700                        $optionLogParams = array(
3701                            'user_id' => $userData['User']['id'],
3702                            'platform' => Configure::read('platform.pclp'),
3703                            'status' => 3,//set to unsubscribe
3704                            'controller_name' => $this->request->params['controller'],
3705                            'action_name' => $this->request->params['action'],
3706                            'user_type' => 0, // user
3707                            'option_before' => 1,
3708                            'option_after' => '',
3709                            'option_before_name' => 'Native Unlimited Option',
3710                            'option_after_name' => '',
3711                            'option_type' => 1,
3712                            'payment_plan_id' => $paymentPlanId
3713                        );
3714
3715                        $_saveLog = ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
3716
3717                        if (!$_saveLog) {
3718                            $this->log(__METHOD__ . ' Failed to update option change. ' . json_encode($optionLogParams), $logFileName);
3719                            $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed to update user data', $optionLogParams);
3720                            return ;
3721                        }
3722                    }
3723
3724                    # add log if change on callan option 
3725                    if ($isliteCallanOptionChange) {
3726
3727                        $optionLogParams = array(
3728                            'user_id' => $userId,
3729                            'platform' => Configure::read('platform.pclp'),
3730                            'status' => 3,//unsubscribe
3731                            'controller_name' => $this->request->params['controller'],
3732                            'action_name' => $this->request->params['action'],
3733                            'user_type' => 0, // user
3734                            'option_before' => 1,
3735                            'option_after' => '',
3736                            'option_before_name' => 'Callan Unlimited Option',
3737                            'option_after_name' => '',
3738                            'option_type' => 2,
3739                            'payment_plan_id' => $paymentPlanId
3740                        );
3741
3742                        $_saveLog = ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
3743
3744                        // rollback if confiscating points failed
3745                        if (!$_saveLog) {
3746                            $this->log(__METHOD__ . ' Failed to save user option change log. --> ' . json_encode($optionLogParams) . ' -- ' . json_encode($data), $logFileName);
3747                                    
3748                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save option log.', $optionLogParams);
3749                            return ;
3750                        }
3751                    }
3752                }
3753                
3754
3755                // NC-7459 check previus user status, add coinbox challenge
3756                if (
3757                    isset($read['User']['payment_plan_id'])
3758                    && $read['User']['payment_plan_id'] == Configure::read('payment_plans.complimentary_plan')
3759                    && isset($read['User']['complimentary_code'])
3760                ) {
3761
3762                    // get complimentary coin award
3763                    $coinAward = $this->ComplimentaryCode->find('first', array(
3764                        'fields' => array('coin_award'),
3765                        'conditions' => array(
3766                            'ComplimentaryCode.code' => $read['User']['complimentary_code'],
3767                            'ComplimentaryCode.template_type !=' => 0 // // Free trial
3768                        )
3769                    ));
3770
3771                    if (
3772                        isset($coinAward['ComplimentaryCode']['coin_award'])
3773                        && $coinAward['ComplimentaryCode']['coin_award']
3774                    ) { // @TODO use common @note did not use CoinBox->addCoinReward because it will not succeed for unknown reason.
3775                        $coinboxSet = array(
3776                            'status' => 1,
3777                            'user_id' => $userData['User']['id'],
3778                            'teacher_id' => null,
3779                            'coin_event_id' => Configure::read('coin_box_event.complimentary'),
3780                            'coin' => $coinAward['ComplimentaryCode']['coin_award'],
3781                            'lesson_id' => NULL,
3782                            'expiration_date' => date('Y-m-d 23:59:59', strtotime('+59 days'))
3783                        );
3784                        $this->CoinBox->create();
3785                        $this->CoinBox->set($coinboxSet);
3786                        if (!$this->CoinBox->save()) {
3787                            CakeLog::debug('[debug_payment_proceed] complimentary coin award : ' . json_encode($saveUserArr));
3788                            $this->log(__METHOD__ . ' Failed adding complimentary coin award . ' . json_encode($saveUserArr) . ' -- ' . json_encode($data) . ' -- ' . json_encode($coinAward), $logFileName);
3789                            $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed adding complimentary coin award', $data, $coinboxSet);
3790                            return ;
3791                        }
3792                    }
3793                }
3794                
3795                $memKey = 'family_reactivation_' . $data['sendid'] . '_' . $familyId;
3796                $familyReactivation = $this->memcache->get($memKey);
3797                // NC-3754 : add memo for reactivation parent user.
3798                if ($formType == Configure::read('payment_credit_family_monthly_payment') && !empty($read['User']['parent_id']) && $familyReactivation) {
3799                    $famRegist = false;
3800                    // delete memcache
3801                    $this->memcache->delete($memKey);
3802                    $this->User->clear();
3803                    if (!$userRead = $this->User->read(array('memo'), $data['sendid'])) {
3804                        $this->log(__METHOD__ . ' User id does not exist. ' . json_encode($data), $logFileName);
3805                        $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'User id does not exist', $data);
3806                        return ;
3807                    }
3808
3809                    $this->User->set(array('memo' => date('Y/m/d H:i:s')." Family plan[User]: family id: " . $userData['User']['id'] . " reactivation \n" . $userRead['User']['memo']));
3810                    $this->User->validate = false;
3811                    if (!$this->User->save()) {
3812                        $this->log(__METHOD__ . ' Failed update user data. ' . json_encode($userRead) . ' -- ' . json_encode($data), $logFileName);
3813                        $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed update user data', $data, $userRead);
3814                        return ;
3815                    }
3816                }
3817
3818                // NC-3754 
3819                // Proccess Family Plan
3820                if($famRegist && !$familyReactivation) {
3821                    // @param:  parent id. for memcache key.
3822                    $famPlanRes = $this->FamilyPlanList->processFamPlan($data['sendid'], $familyId, $data['sendpoint']);
3823                    if ($famPlanRes != "[OK]") {
3824                        $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], $famPlanRes, $data);
3825                        return;
3826                    }
3827                }
3828
3829                // check if membership status was change
3830                if (isset($ptPaymentParams['statusBefore']) && isset($ptPaymentParams['statusAfter']) && isset($ptPaymentParams['platform'])) {
3831                    $currentUser = $this->User->find('first', array(
3832                        'fields' => array(
3833                            'User.parent_id', 
3834                            'User.currency_code', 
3835                            'User.payment_plan_id',
3836                            'User.native_option', 
3837                            'User.callan_option'
3838                        ),
3839                        'conditions' => array('User.id' => $userId),
3840                        'recursive' => -1
3841                    ));
3842                    $parentId = $currentUser['User']['parent_id'];
3843                    $is_cron = 0;
3844                    if (php_sapi_name() == 'cli' || $ptPaymentParams['logFileName'] == 'retry_monthly_payment'){
3845                        $is_cron = 1;
3846                    } 
3847                       $currency_after = $currentUser['User']['currency_code'];
3848                       $plan_after = $currentUser['User']['payment_plan_id'];
3849
3850                    $usclData = array(
3851                        'user_id' => $userId,
3852                        'platform' => $ptPaymentParams['platform'] ?? '',
3853                        'card_company_before' => $read['User']['card_company'],
3854                        'status_before' => $ptPaymentParams['statusBefore'],
3855                        'status_after' => $ptPaymentParams['statusAfter'],
3856                        'controller_name' => $this->request->params['controller'],
3857                        'action_name' => $this->request->params['action'],
3858                        'parent_id' => $parentId,
3859                        'is_cron' => $is_cron,
3860                        'currency_before' => $currency_before,
3861                        'currency_after' => $currency_after,
3862                        'payment_plan_id_before' => $plan_before,
3863                        'payment_plan_id_after' => $plan_after,
3864                        'default_appreciation_flg' => $appreciationFlg,
3865                        'default_appreciation_amount' => $tipAmount
3866                    );
3867                    // save user change membership status
3868                    if (!$this->UserStatusChangeLog->saveLog($usclData)) {
3869                        $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'Unable to update status change log', $usclData);
3870                        return;
3871                    }
3872
3873                    //- Update users if changed to a light plan and has options
3874                    if (in_array($plan_after, Configure::read('lite_payment_plans'))) {
3875                        $optionsToUpdate = [];
3876
3877                        //- Check and prepare the options to update
3878                        if (!empty($currentUser['User']['native_option'])) {
3879                            $optionsToUpdate['native_option'] = 0;
3880                            $optionsToUpdate['native_option_cancellation_time'] = date('Y-m-d H:i:s');
3881                        }
3882
3883                        if (!empty($currentUser['User']['callan_option'])) {
3884                            $optionsToUpdate['callan_option'] = 0;
3885                            $optionsToUpdate['callan_option_cancellation_time'] = date('Y-m-d H:i:s');
3886                        }
3887
3888                        //- If there are options to update, proceed
3889                        if (!empty($optionsToUpdate)) {
3890                            $optionsToUpdate['id'] = $userId;
3891                            $this->User->set($optionsToUpdate);
3892                            
3893                            if (!$this->User->save()) {
3894                                $this->log(__METHOD__ . ' Failed to update user data. ' . json_encode($optionsToUpdate), $logFileName);
3895                                $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'Failed to update user data', $optionsToUpdate);
3896                                return;
3897                            }
3898                        }
3899                    }
3900                }
3901
3902                # check if user is temporary
3903                if (
3904                    ($userData['User']['status'] == 0 && $formType == Configure::read('payment_credit_authentication')) || 
3905                    ($userData['User']['status'] == 0 && $formType == Configure::read('payment_lite_credit_free') ) ||
3906                    ($userData['User']['status'] == 0 && $formType == Configure::read('payment_credit_chocotto_free') )
3907                ) {
3908                    # update user's status after step 4
3909                    $this->User->validate = array();
3910                    if (!$this->User->read(null, $userData['User']['id'])) {
3911                        $this->log(__METHOD__ . ' User id does not exist. ' . json_encode($userData), $logFileName);
3912                        $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'User id does not exist', $userData);
3913                        return ;
3914                    }
3915                    $this->User->set('status', 1);
3916                    if (!$this->User->save()) {
3917                        $this->log(__METHOD__ . ' Failed update user status to 1. ' . json_encode($data), $logFileName);
3918                        $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed update user status to 1', $data);
3919                        return ;
3920                    }
3921                }
3922
3923                // NC-7779 : check if user has chivox monthly test taken for the current month, and monthly_speaking_attended_flg ON,
3924                // turn Off the flag if users has not yet taken the exam for the current month.
3925                // @TODO check query
3926                if (
3927                    isset($userData['User']['monthly_speaking_attended_flg']) && isset($userData['User']['monthly_speaking_business_attended_flg'])
3928                    && ($userData['User']['monthly_speaking_attended_flg'] == 1 || $userData['User']['monthly_speaking_business_attended_flg'] == 1)
3929                ) {
3930
3931                    // check chivox monthly
3932                    $paymentPlanIdsForChivoxMonthly = Configure::read('chivox.monthly.user_payment_plan_cantake_exam');
3933                    if (in_array($paymentPlanId, $paymentPlanIdsForChivoxMonthly)) {
3934
3935                        // load model
3936                        $this->loadModel("UsersChivoxMonthlyTest");
3937                        $userTestMonthFlagParams['user_id'] = $userData['User']['id'];
3938                        $userTestMonthFlag = $this->UsersChivoxMonthlyTest->checkUserCurrentMonthExam($userTestMonthFlagParams);
3939
3940                        $monthly_speaking_attended_flg = Configure::read('chivox.test_data_test_type.daily'); // test_type daily speaking 0
3941                        $monthly_speaking_business_attended_flg = Configure::read('chivox.test_data_test_type.business'); // test_type business 1
3942                        $fieldsToUpdate = array();
3943
3944                        // if user hat not yet taken the exam for current month
3945                        if (!in_array($monthly_speaking_attended_flg, $userTestMonthFlag)) {
3946                            $fieldsToUpdate['monthly_speaking_attended_flg'] = 0;
3947                        }
3948                        if (!in_array($monthly_speaking_business_attended_flg, $userTestMonthFlag)) {
3949                            $fieldsToUpdate['monthly_speaking_business_attended_flg'] = 0;
3950                        }
3951
3952                        if ($fieldsToUpdate) {
3953                            $this->User->validate = array();
3954                            if (!$this->User->read(null, $userData['User']['id'])) {
3955                                $this->log(__METHOD__ . ' [NC-7779] User id does not exist. ' . json_encode($userData), $logFileName);
3956                                $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'User id does not exist', $userData);
3957                                return ;
3958                            }
3959                            $this->User->set($fieldsToUpdate);
3960                            if (!$this->User->save()) {
3961                                $this->log(__METHOD__ . ' [NC-7779] Failed update user monthly_speaking_attended_flg or monthly_speaking_business_attended_flg to 0. ' . json_encode($data), $logFileName);
3962                                $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed update user monthly_speaking_attended_flg to 0', $data);
3963                                return ;
3964                            }
3965                        }
3966                    }
3967                }
3968            }
3969
3970            $annualDiscountOption = isset($ptPaymentParams['annualDiscountOption']) ? $ptPaymentParams['annualDiscountOption'] : [];
3971            // if user cancel annual discount option
3972            if (
3973                $annualDiscountOption &&
3974                isset($annualDiscountOption['cancellation_fee']) &&
3975                $formType == Configure::read('payment_halfway_termination_of_annual_discount_option')
3976            ) {
3977                $doshData = [
3978                    'user_id' => $userId,
3979                    'discount_option_term_id' => $annualDiscountOption['discount_option_term_id'],
3980                    'discount_option_id' => $annualDiscountOption['discount_option_id'],
3981                    'discount_option_price_id' => $annualDiscountOption['discount_option_price_id'],
3982                    'payment_id' => $paymentSaveID,
3983                    'event' => $annualDiscountOption['dosh_event'],
3984                    'amount' => $annualDiscountOption['cancellation_fee'],
3985                    'currency_code' => $currencyCode,
3986                    'type' => $annualDiscountOption['dosh_type'],
3987                    'status' => $annualDiscountOption['dosh_status'],
3988                    'settlement_status' => 1 // success
3989                ];
3990
3991                // create discount option settlement history
3992                if (!$res = $this->DiscountOptionsSettlementHistory->createHistory($doshData)) {
3993                    $this->log(__METHOD__ . ' Failed to create discount option settlement history. ' . json_encode($doshData), $logFileName);
3994                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to create discount option settlement history. ', $doshData);
3995                    return ;
3996                }
3997
3998                // stop user annual discount option term
3999                if (!$this->UserDiscountOptionsTerm->stopTerm(['userId' => $userId])) {
4000                    $this->log(__METHOD__ . ' Failed to stop annual discount option term. ' . json_encode(['userId' => $userId]), $logFileName);
4001                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to stop annual discount option term.', ['userId' => $userId]);
4002                    return ;
4003                }
4004
4005                // update user memo
4006                $memo = date('Y/m/d H:i') . " 年間割引オプション解約\n" . $userData['User']['memo'];
4007                if (!$this->User->updateUserById(['userData' => ['memo' => $memo], 'id' => $userId])) {
4008                    $this->log(__METHOD__ . ' Failed to update user memo. ' . json_encode($memo) . ' id: ' . json_encode($userId), $logFileName);
4009                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to stop annual discount option term.', [$memo]);
4010                    return ;
4011                }
4012                
4013                $adoLogParams = [
4014                    'user_id' => $userId,
4015                    'platform' => $platform,
4016                    'status' => 1, // subscribe
4017                    'controller_name' => $this->request->params['controller'],
4018                    'action_name' => $this->request->params['action'],
4019                    'user_type' => 0, // normal user
4020                    'option_before' => 1,
4021                    'option_after' => '',
4022                    'option_before_name' => 'Annual Discount Option',
4023                    'option_after_name' => '',
4024                    'option_type' => 3, // annual discount option
4025                    'payment_plan_id' => $paymentPlanId
4026                ];
4027
4028                if (!$this->UserOptionChangeLog->saveOptionChangeLog($adoLogParams)) {
4029                    $this->log(__METHOD__ . ' Failed to update option change. ' . json_encode($adoLogParams), $logFileName);
4030                    $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'Failed to update user data', $adoLogParams);
4031                    return ;
4032                }
4033            }
4034
4035            // if payment was saved, and form type belongs to textbook purchase,
4036            // update textbook_sales table, insert payment_id
4037            if ($formType == Configure::read('payment_credit_textbook_purchase')) {
4038                // set textbook sales info
4039                $textbookSales = $this->TextbookSale->find('first', array(
4040                    'conditions' => array(
4041                        'TextbookSale.sales_code' => $ptPassword
4042                    ),
4043                    'recursive' => -1
4044                ));
4045                
4046                // if has textbook sales, update payment_id
4047                if ($textbookSales) {
4048                    $this->TextbookSale->clear();
4049                    if (!$this->TextbookSale->read(null, $textbookSales['TextbookSale']['id'])) {
4050                        $this->log(__METHOD__ . ' Textbook sales id does not exist. ' . json_encode($textbookSales), $logFileName);
4051                        $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'Textbook sales id does not exist', $textbookSales);
4052                        return ;
4053                    }
4054                    $this->TextbookSale->set('payment_id', $this->Payment->id);
4055                    $this->TextbookSale->set('payment_status', 1);
4056                    if (!$this->TextbookSale->save()) {
4057                        $this->log(__METHOD__ . ' Failed update textbook sales payment status to 1. ' . json_encode($textbookSales), $logFileName);
4058                        $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'Failed update textbook sales payment status to 1', $textbookSales);
4059                        return ;
4060                    }
4061                }
4062            }
4063
4064            // If Chocotto user, set active_flg to 0
4065            // check if has complimentary code, set active_flg to 0
4066            if (in_array($formType, array(
4067                    Configure::read('payment_credit_chocotto_free'),
4068                    Configure::read('payment_credit_chocotto_monthly_payment'),
4069                    Configure::read('payment_credit_chocotto_force_charge')
4070                )) && $compCodeData = $this->CompCodeUsage->ifHasActiveComplimentaryCode($userData['User']['id'])
4071            ) {
4072                $this->CompCodeUsage->updateAll(
4073                    array(
4074                        'active_flg' => 0
4075                    ),
4076                    array(
4077                        'user_id' => $userData['User']['id'],
4078                        'active_flg' => 1,
4079                        'code' => $compCodeData['CompCodeUsage']['code']
4080                    )
4081                );
4082            }
4083
4084            // [ZEUS] check if receivable payment sent was either
4085            // receivable payment, monthly payment, force settlement, or retry payment
4086            // if yes, set receivable payments to "received"
4087            if (
4088                in_array($formType, array(
4089                    Configure::read('payment_credit_appreciation_receivable'),
4090                    Configure::read('payment_credit_receivable'),
4091                    Configure::read('payment_credit_monthly_payment'),
4092                    Configure::read('payment_credit_force_charge'),
4093                    Configure::read('payment_credit_retry'),
4094                    Configure::read('payment_credit_family_monthly_payment'),
4095                    Configure::read('payment_lite_credit_monthly_payment'),
4096                    Configure::read('payment_lite_credit_paid'),
4097                    Configure::read('payment_lite_plan_downgrade'),
4098                    Configure::read('payment_lite_plan_upgrade'),
4099                    Configure::read('payment_credit_change'),
4100                    Configure::read('payment_credit_chocotto_monthly_payment'),
4101                    Configure::read('payment_credit_chocotto_retry'),
4102                    Configure::read('payment_credit_chocotto_force_charge')
4103                ))
4104            ) {
4105                // get current payment_id
4106                $paymentID = $this->Payment->id;
4107
4108                // create new payment receivable
4109                if ($formType != Configure::read('payment_credit_receivable') && $receivablePayment) {
4110                    // set payment id
4111                    $data["payment_id"] = $paymentID;
4112
4113                    $paymentData = array(
4114                        'user_id' => $userId,
4115                        'amount' => $receivablePayment,
4116                        'status' => 1,
4117                        'type_id' => 1,
4118                        'reference_id' => $referenceId,
4119                        'card_company' => $card_company,
4120                        'param1' => json_encode($data),
4121                        'form_type' => Configure::read('payment_credit_receivable'),
4122                        'ordd' => $data["ordd"],
4123                        'currency_code' => Configure::read('currency_jpy'), // set currency id to jpy
4124                        'transaction_code' => $paymentHash,
4125                        'price_id' => $priceId,
4126                        'payment_id' => $paymentPlanId,
4127                        'payment_type' => $paymentType,
4128                        'discounted_amount' => 0
4129                    );
4130
4131                    // create new payment
4132                    $this->Payment->clear();
4133                    $this->Payment->create();
4134                    $this->Payment->set($paymentData);
4135                    if (!$this->Payment->save()) {
4136                        $this->log(__METHOD__ . ' Failed to save payment data' . json_encode($paymentData), $logFileName);
4137                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data', $paymentData);
4138                        return ;
4139                    }
4140
4141                    //update/add user`s settlement amount
4142                    $this->User->updateUserPayments($paymentData);
4143                    // set payment_id
4144                    $paymentID = $this->Payment->id;
4145
4146                }
4147
4148                // set payment receivable statuses to 2 - received
4149                $this->PaymentReceivable->updateReceivableReservationPayment(
4150                    $userData['User']['id'], 
4151                    array(
4152                        'status' => 2,
4153                        'payment_id' => $paymentID,
4154                        'payment_collection_date' => date("Y-m-d H:i:s"),
4155                        'card_company' => $card_company,
4156                        'payment_plan_id' => $paymentPlanId,
4157                        'membership_type_index' => $membershipStatusIndex
4158                    ),
4159                    array(
4160                        'PaymentReceivable.user_id' => $userData['User']['id'],
4161                        'PaymentReceivable.status' => 0,
4162                        'PaymentReceivable.payment_element_type' => 1,
4163                        'PaymentReceivable.created <=' => $cronDateRun
4164                    )
4165                );
4166
4167                // debug log
4168                $this->log("[ZEUSPAY_RECEIVABLE] kickback was recieved -> " . json_encode($data), $logFileName);
4169
4170                // create new payment for appreciation receivable
4171                if ($formType != Configure::read('payment_credit_appreciation_receivable') && $appreciationReceivable > 0) {
4172                    // set payment id
4173                    $data["payment_id"] = $paymentID;
4174                    //reset payment data
4175                    $paymentData = array();
4176
4177                    //set payment data
4178                    $paymentData = array(
4179                        'user_id' => $userId,
4180                        'amount' => $appreciationReceivable,
4181                        'status' => 1,
4182                        'type_id' => 1,
4183                        'reference_id' => $referenceId,
4184                        'card_company' => $card_company,
4185                        'param1' => json_encode($data),
4186                        'form_type' => Configure::read('appreciation_data.payment_form_type'),
4187                        'ordd' => $data["ordd"],
4188                        'currency_code' => Configure::read('currency_jpy'), // set currency id to jpy
4189                        'transaction_code' => $paymentHash,
4190                        'price_id' => $priceId,
4191                        'payment_id' => $paymentPlanId,
4192                        'payment_type' => $paymentType,
4193                        'discounted_amount' => 0
4194                    );
4195
4196                    // create new payment
4197                    $this->Payment->clear();
4198                    $this->Payment->create();
4199                    $this->Payment->set($paymentData);
4200                    if (!$this->Payment->save()) {
4201                        $this->log(__METHOD__ . ' Failed to save appreciationReceivable payment data' . json_encode($paymentData), $logFileName);
4202                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save appreciationReceivable payment data', $paymentData);
4203                        return ;
4204                    }
4205                    //update/add user`s settlement amount
4206                    $this->User->updateUserPayments($paymentData);
4207                    // set payment_id
4208                    $paymentID = $this->Payment->id;
4209
4210                }
4211
4212                // set payment receivable for appreciation statuses to 2 - received
4213                $this->PaymentReceivable->updateReceivableReservationPayment(
4214                    $userData['User']['id'], 
4215                    array(
4216                        'status' => 2,
4217                        'payment_id' => $paymentID,
4218                        'payment_collection_date' => date("Y-m-d H:i:s"),
4219                        'card_company' => $card_company,
4220                        'payment_plan_id' => $paymentPlanId,
4221                        'membership_type_index' => $membershipStatusIndex
4222                    ),
4223                    array(
4224                        'PaymentReceivable.user_id' => $userData['User']['id'],
4225                        'PaymentReceivable.status' => 0,
4226                        'PaymentReceivable.payment_element_type' => Configure::read('appreciation_data.payment_element_type'),
4227                        'PaymentReceivable.created <=' => $cronDateRun
4228                    )
4229                );
4230
4231                // debug log
4232                $this->log("[ZEUSPAY_APPRECIATION_RECEIVABLE] kickback was recieved -> " . json_encode($data), $logFileName);
4233
4234                // create new payment for live lesson receivable
4235                if ($formType != Configure::read('payment_live_lesson_receivable') && $liveLessonReceivable) {
4236                    // set payment id
4237                    $data["payment_id"] = $paymentID;
4238
4239                    $paymentData = array(
4240                        'user_id' => $userId,
4241                        'amount' => $liveLessonReceivable,
4242                        'status' => 1,
4243                        'type_id' => 1,
4244                        'reference_id' => $referenceId,
4245                        'card_company' => $card_company,
4246                        'param1' => json_encode($data),
4247                        'form_type' => Configure::read('payment_live_lesson_receivable'),
4248                        'ordd' => $data["ordd"],
4249                        'currency_code' => Configure::read('currency_jpy'), // set currency id to jpy
4250                        'transaction_code' => $paymentHash,
4251                        'price_id' => $priceId,
4252                        'payment_id' => $paymentPlanId,
4253                        'payment_type' => $paymentType,
4254                        'discounted_amount' => 0
4255                    );
4256
4257                    // create new payment
4258                    $this->Payment->clear();
4259                    $this->Payment->create();
4260                    $this->Payment->set($paymentData);
4261                    if (!$this->Payment->save()) {
4262                        $this->log(__METHOD__ . ' Failed to save payment data' . json_encode($paymentData), $logFileName);
4263                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data', $paymentData);
4264                        return ;
4265                    }
4266                    //update/add user`s settlement amount
4267                    $this->User->updateUserPayments($paymentData);
4268                    // set payment_id
4269                    $paymentID = $this->Payment->id;
4270                }
4271
4272                // set payment receivable for live lesson statuses to 2 - received
4273                $this->PaymentReceivable->updateReceivableReservationPayment(
4274                    $userData['User']['id'], 
4275                    array(
4276                        'status' => 2,
4277                        'payment_id' => $paymentID,
4278                        'payment_collection_date' => date("Y-m-d H:i:s"),
4279                        'card_company' => $card_company,
4280                        'payment_plan_id' => $paymentPlanId,
4281                        'membership_type_index' => $membershipStatusIndex
4282                    ),
4283                    array(
4284                        'PaymentReceivable.user_id' => $userData['User']['id'],
4285                        'PaymentReceivable.status' => 0,
4286                        'PaymentReceivable.payment_element_type' => Configure::read('payment_element_type.live'),
4287                        'PaymentReceivable.created <=' => $cronDateRun
4288                    )
4289                );
4290                
4291                // debug log
4292                $this->log("[ZEUSPAY_LIVE_RECEIVABLE] kickback was recieved -> " . json_encode($data), $logFileName);                
4293
4294            }
4295
4296            // NC-7029: CHECK REFERRAL USER
4297            if (
4298                in_array($formType, array(
4299                    Configure::read('payment_credit_monthly_payment'),
4300                    Configure::read('payment_credit_force_charge'),
4301                    Configure::read('payment_credit_retry'),
4302                    Configure::read('payment_credit_authentication'),
4303                    Configure::read('payment_credit_family_monthly_payment'),
4304                    Configure::read('payment_lite_credit_monthly_payment'),
4305                    Configure::read('payment_lite_credit_paid')
4306                ))
4307            ) {
4308                $ruData = array(
4309                    'referee_id' => $userData['User']['id'],
4310                    'payment_plan_id' => $newYear95percentOffCampaign ? Configure::read('payment_plans.free_trial') : $paymentPlanId,
4311                    'currency_code' => $userData['User']['currency_code'],
4312                    'logFileName' => $logFileName,
4313                    'form_type' => $newYear95percentOffCampaign ? Configure::read('payment_credit_authentication') : $formType
4314                );
4315
4316                $couponReferredData = $this->UsersReferral->checkReferredUser($ruData);
4317                if (isset($couponReferredData['error']) && $couponReferredData['error']) {
4318                    $this->log(__METHOD__ . ' Failed to update users referral event flg.' . json_encode($ruData), $logFileName);
4319                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update users referral event flg.', $ruData);
4320                    return ;
4321                }
4322
4323                $couponMailId = Configure::read('site_in_mail.coupon_mail_template_id');
4324
4325                // send coupon mail to referee
4326                if (isset($couponReferredData['sendMailToReferee']) && $couponReferredData['sendMailToReferee']) {
4327                    $refereeData = array(
4328                        'id' => $userData['User']['id'],
4329                        'email' => $userData['User']['email'],
4330                        'native_language2' => $userData['User']['native_language2'],
4331                        'hash' => $userData['User']['hash'],
4332                        'refereeName' => $userData['User']['nickname'],
4333                        'referrerName' => $couponReferredData['referrerName'],
4334                        'couponAmount' => $couponReferredData['refereeSaveAmount'],
4335                        'couponUpdatedTotal' => $couponReferredData['refereeUpdatedTotal']
4336                    );
4337
4338                    // send mail to referee
4339                    myMailer::sendTemplateMail($couponMailId, $userData['User']['email'], $refereeData, array(), 'User');
4340                }
4341
4342                // send coupon mail to referer
4343                if (isset($couponReferredData['sendMailToReferer']) && $couponReferredData['sendMailToReferer']) {
4344                    $referrerData = array(
4345                        'id' => $couponReferredData['referrerId'],
4346                        'email' => $couponReferredData['referrerEmail'],
4347                        'native_language2' => $couponReferredData['nativeLanguage2'],
4348                        'hash' => $couponReferredData['referrerHash'],
4349                        'refereeName' => $userData['User']['nickname'],
4350                        'referrerName' => $couponReferredData['referrerName'],
4351                        'couponAmount' => $couponReferredData['refererSaveAmount'],
4352                        'couponUpdatedTotal' => $couponReferredData['refererUpdatedTotal']
4353                    );
4354
4355                    // send mail to referrer
4356                    myMailer::sendTemplateMail($couponMailId, $couponReferredData['referrerEmail'], $referrerData, array(), 'User');
4357                }
4358
4359                
4360                if ( //Amazon gift campaign
4361                    in_array($formType, array(
4362                        Configure::read('payment_credit_force_charge'),
4363                        Configure::read('payment_credit_authentication')
4364                    ))
4365                ) {
4366                    ClassRegistry::init('CampaignSettingTable')->amazonGift(array('user_id' => $userData['User']['id'], 'type' => 1));
4367                }
4368            }
4369            
4370            // NJ-47740
4371            $getCouponDiscounDetail = PaymentTable::getCouponDiscountRequestDetail($ptPaymentParams, 'native');
4372            $nativeOptionDiscount = !empty($getCouponDiscounDetail['discounted_amount']) ? $getCouponDiscounDetail['discounted_amount'] : 0;
4373            $nativeCouponRequestId = !empty($getCouponDiscounDetail['coupon_request_id']) ? $getCouponDiscounDetail['coupon_request_id'] : null;
4374            // if has native speaker payment
4375            if (
4376                isset($ptPaymentParams['nativeOptionPayment']) && ($ptPaymentParams['nativeOptionPayment'] > 0 || $nativeOptionDiscount > 0)
4377                && in_array($ptPaymentParams['formType'], array(Configure::read('payment_credit_monthly_payment'), Configure::read('payment_credit_family_monthly_payment')))
4378            ) {
4379                $nspFormType = Configure::read('payment_native_option_monthly_payment');
4380                if (isset($ptPaymentParams['nativeOptionJoin']) && $ptPaymentParams['nativeOptionJoin']) {
4381                    $nspFormType = Configure::read('payment_native_option_join');
4382                }
4383                
4384                // check if family plan
4385                if ($familyId) {
4386                    // change reference id to parent id
4387                    $referenceId = isset($data['sendid']) ? $data['sendid'] : 0;
4388                } else {
4389                    $referenceId = $userId;
4390                }
4391
4392                $paymentData = array(
4393                    'user_id' => $userId,
4394                    'amount' => $ptPaymentParams['nativeOptionPayment'],
4395                    'status' => 1,
4396                    'type_id' => 1,
4397                    'reference_id' => $referenceId,
4398                    'payment_transaction_password' => $ptPassword,
4399                    'card_company' => $card_company,
4400                    'param1' => json_encode($data),
4401                    'form_type' => $nspFormType,
4402                    'ordd' => $data["ordd"],
4403                    'currency_code' => Configure::read('currency_jpy'),
4404                    'transaction_code' => $paymentHash,
4405                    'price_id' => $priceId,
4406                    'payment_id' => $paymentPlanId,
4407                    'payment_type' => Configure::read('payment_types.native_option'),
4408                );
4409                
4410                // NJ-47740
4411                $paymentData['discounted_amount'] = $nativeOptionDiscount;
4412                $paymentData['coupon_request_id'] = $nativeCouponRequestId;
4413
4414                // create new payment
4415                $this->Payment->clear();
4416                $this->Payment->create();
4417                $this->Payment->set($paymentData);
4418                if (!$this->Payment->save()) {
4419                    $this->log(__METHOD__ . ' Failed to save payment data' . json_encode($paymentData), $logFileName);
4420                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data', $paymentData);
4421                    return ;
4422                }
4423                
4424                //update/add user`s settlement amount
4425                $this->User->updateUserPayments($paymentData);
4426                
4427                // NJ-47740
4428                if (!empty($paymentData['coupon_request_id']) && $paymentData['discounted_amount'] > 0) {
4429                    // confirm coupon use request for native discount
4430                    $requestCouponConfirmData = array(
4431                        'grpId' => $paymentData['coupon_request_id'],
4432                        'paymentId' => $this->Payment->id
4433                    );
4434                    $result_confirm = $this->UsersCouponV1->performCouponConfirm($requestCouponConfirmData);
4435                    
4436                    if (!$result_confirm) {
4437                        $this->log(__METHOD__ . ' Failed to confirm native coupon use request. ' . json_encode($requestCouponConfirmData) . ' -- ' . json_encode($data), $logFileName);
4438                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to confirm native coupon use request', $data, $requestCouponConfirmData);
4439                        return ;
4440                    }
4441                }
4442                // NJ-47740 end
4443                
4444                // update payment details
4445                $updatePaymentDetailParams = array(
4446                    'currencyCode' => $paymentData['currency_code'],
4447                    'formType' => $paymentData['form_type'],
4448                    'paymentType' => $paymentData['payment_type'],
4449                    'amount' => $paymentData['amount'],
4450                    'discounted_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0,
4451                    'familyId' => $familyId,
4452                    'cronDateRun' => $cronDateRun,
4453                    'priceId' => $paymentData['price_id'],
4454                    'paymentPlanId' => $paymentData['payment_id'],
4455                    'user_id' => $paymentData['user_id'],
4456                    'coupon_use_request_id' => isset($paymentData['coupon_request_id']) ? $paymentData['coupon_request_id'] : null,
4457                    'coupon_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0
4458                );
4459                
4460                $updatePaymentDetail = array(
4461                    'id' => $ptId,
4462                    'fields' => array(
4463                        'payment_details' => $updatePaymentDetailParams
4464                    )
4465                );
4466
4467                if (!$this->PaymentTransaction->updateWPPaymentTransaction($updatePaymentDetail)) {
4468                    $this->log(__METHOD__ . ' Failed to update payment details. ' . json_encode($updatePaymentDetail), $logFileName);
4469                }
4470            }
4471
4472            // if has callan option payment
4473            // NJ-47740
4474            $getCouponDiscounDetail = PaymentTable::getCouponDiscountRequestDetail($ptPaymentParams, 'callan');
4475            $callanOptionDiscount = !empty($getCouponDiscounDetail['discounted_amount']) ? $getCouponDiscounDetail['discounted_amount'] : 0;
4476            $callanCouponRequestId = !empty($getCouponDiscounDetail['coupon_request_id']) ? $getCouponDiscounDetail['coupon_request_id'] : null;
4477            if (
4478                isset($ptPaymentParams['callanOptionPayment']) && ($ptPaymentParams['callanOptionPayment'] > 0 || $callanOptionDiscount > 0)
4479                && in_array($ptPaymentParams['formType'], array(Configure::read('payment_credit_monthly_payment'), Configure::read('payment_credit_family_monthly_payment')))
4480            ) {
4481                $nspFormType = Configure::read('payment_callan_option_monthly_payment');
4482                if (isset($ptPaymentParams['callanOptionJoin']) && $ptPaymentParams['callanOptionJoin']) {
4483                    $nspFormType = Configure::read('payment_callan_option_join');
4484                }
4485                
4486                // check if family plan
4487                if ($familyId) {
4488                    // change reference id to parent id
4489                    $referenceId = isset($data['sendid']) ? $data['sendid'] : 0;
4490                } else {
4491                    $referenceId = $userId;
4492                }
4493
4494                $paymentData = array(
4495                    'user_id' => $userId,
4496                    'amount' => $ptPaymentParams['callanOptionPayment'],
4497                    'status' => 1,
4498                    'type_id' => 1,
4499                    'reference_id' => $referenceId,
4500                    'payment_transaction_password' => $ptPassword,
4501                    'card_company' => $card_company,
4502                    'param1' => json_encode($data),
4503                    'form_type' => $nspFormType,
4504                    'ordd' => $data["ordd"],
4505                    'currency_code' => Configure::read('currency_jpy'),
4506                    'transaction_code' => $paymentHash,
4507                    'price_id' => $priceId,
4508                    'payment_id' => $paymentPlanId,
4509                    'payment_type' => Configure::read('payment_types.callan_option'),
4510                );
4511                
4512                // NJ-47740
4513                $paymentData['discounted_amount'] = $callanOptionDiscount;
4514                $paymentData['coupon_request_id'] = $callanCouponRequestId;
4515
4516                // create new payment
4517                $this->Payment->clear();
4518                $this->Payment->create();
4519                $this->Payment->set($paymentData);
4520                if (!$this->Payment->save()) {
4521                    $this->log(__METHOD__ . ' Failed to save payment data' . json_encode($paymentData), $logFileName);
4522                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data', $paymentData);
4523                    return ;
4524                }
4525                
4526                //update/add user`s settlement amount
4527                $this->User->updateUserPayments($paymentData);
4528
4529                // NJ-47740
4530                if (!empty($paymentData['coupon_request_id']) && $paymentData['discounted_amount'] > 0) {
4531                    // confirm coupon use request for callan discount
4532                    $requestCouponConfirmData = array(
4533                        'grpId' => $paymentData['coupon_request_id'],
4534                        'paymentId' => $this->Payment->id
4535                    );
4536                    $result_confirm = $this->UsersCouponV1->performCouponConfirm($requestCouponConfirmData);
4537
4538                    if (!$result_confirm) {
4539                        $this->log(__METHOD__ . ' Failed to confirm callan coupon use request. ' . json_encode($requestCouponConfirmData) . ' -- ' . json_encode($data), $logFileName);
4540                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to confirm callan coupon use request', $data, $requestCouponConfirmData);
4541                        return;
4542                    }
4543                }
4544                // NJ-47740 end
4545                
4546                // update payment details
4547                $updatePaymentDetailParams = array(
4548                    'currencyCode' => $paymentData['currency_code'],
4549                    'formType' => $paymentData['form_type'],
4550                    'paymentType' => $paymentData['payment_type'],
4551                    'amount' => $paymentData['amount'],
4552                    'discounted_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0,
4553                    'familyId' => $familyId,
4554                    'cronDateRun' => $cronDateRun,
4555                    'priceId' => $paymentData['price_id'],
4556                    'paymentPlanId' => $paymentData['payment_id'],
4557                    'user_id' => $paymentData['user_id'],
4558                    'coupon_use_request_id' => isset($paymentData['coupon_request_id']) ? $paymentData['coupon_request_id'] : null,
4559                    'coupon_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0
4560                );
4561                
4562                $updatePaymentDetail = array(
4563                    'id' => $ptId,
4564                    'fields' => array(
4565                        'payment_details' => $updatePaymentDetailParams
4566                    )
4567                );
4568
4569                if (!$this->PaymentTransaction->updateWPPaymentTransaction($updatePaymentDetail)) {
4570                    $this->log(__METHOD__ . ' Failed to update payment details. ' . json_encode($updatePaymentDetail), $logFileName);
4571                }
4572            }
4573            
4574            // activate the user native option (new, resume, and monthly payment)
4575            if (isset($ptPaymentParams['nativeOptionPayment']) && ($ptPaymentParams['nativeOptionPayment'] > 0 || $nativeOptionDiscount > 0)) { 
4576
4577                $this->log(__METHOD__ . ' NJ-2388 debug Payment Transaction Data: ' . json_encode($ptData), 'native_option_debug');
4578
4579                // - option process data
4580                $optionProcessData = array(
4581                    'user_id' => $userId,
4582                    'type' => 'on',
4583                    'option_type' => Configure::read('native_speaker.options.all_you_can_eat')
4584                );
4585
4586                $this->User->userNativeOptionProcess($optionProcessData);
4587
4588                //NJ-2814 add logs
4589                if (isset($ptPaymentParams['nativeOptionJoin']) && $ptPaymentParams['nativeOptionJoin']) {
4590                    $nativeStatus = 1; // subscribed
4591                    $statusBefore = '';
4592                } else {
4593                    $nativeStatus = 2; // Monthly Continue
4594                    $statusBefore = 1;
4595                }
4596
4597                $optionAfterName = 'Native Unlimited Option';
4598
4599                $optionLogParams = array(
4600                    'user_id' => $userId,
4601                    'platform' => $ptPaymentParams['platform'],
4602                    'status' => $nativeStatus,
4603                    'controller_name' => $this->request->params['controller'],
4604                    'action_name' => $this->request->params['action'],
4605                    'user_type' => 0, // user
4606                    'option_before' => $statusBefore,
4607                    'option_after' => 1,
4608                    'option_before_name' => '',
4609                    'option_after_name' => $optionAfterName,
4610                    'option_type' => 1,
4611                    'payment_plan_id' => $paymentPlanId
4612                );
4613
4614                ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
4615
4616                // - save registration status step
4617                $stepKey = Configure::read('registration_steps.user_info_entry');
4618                $this->saveStep($userId, $stepKey);
4619            }
4620
4621            // activate the user native option (new, resume, and monthly payment)
4622            if (isset($ptPaymentParams['callanOptionPayment']) && ($ptPaymentParams['callanOptionPayment'] > 0 || $callanOptionDiscount > 0)) { 
4623
4624                $this->log(__METHOD__ . ' NJ-2388 debug Payment Transaction Data: ' . json_encode($ptData), 'native_option_debug');
4625
4626                // - option process data
4627                $optionProcessData = array(
4628                    'user_id' => $userId,
4629                    'type' => 'on',
4630                    'option_type' => Configure::read('callan_unlimited.options.callan_unlimited_option')
4631                );
4632
4633                $this->User->userNativeOptionProcess($optionProcessData);
4634
4635                //NJ-2814 add logs
4636                if (isset($ptPaymentParams['callanOptionJoin']) && $ptPaymentParams['callanOptionJoin']) {
4637                    $nativeStatus = 1; // subscribed
4638                    $statusBefore = '';
4639                } else {
4640                    $nativeStatus = 2; // Monthly Continue
4641                    $statusBefore = 1;
4642                }
4643                $optionAfterName = 'Callan Unlimited Option';
4644                $optionLogParams = array(
4645                    'user_id' => $userId,
4646                    'platform' => $ptPaymentParams['platform'],
4647                    'status' => $nativeStatus,
4648                    'controller_name' => $this->request->params['controller'],
4649                    'action_name' => $this->request->params['action'],
4650                    'user_type' => 0, // user
4651                    'option_before' => $statusBefore,
4652                    'option_after' => 1,
4653                    'option_before_name' => '',
4654                    'option_after_name' => $optionAfterName,
4655                    'option_type' => 2,
4656                    'payment_plan_id' => $paymentPlanId
4657                );
4658
4659                ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
4660            }
4661
4662            // if parent user update children's card company
4663            if ($formType == Configure::read('payment_credit_change')) {
4664                $childList = $this->User->getChildId($userId);
4665
4666                // check if user is parent
4667                if (!empty($childList)) {
4668                    foreach ($childList as $childId) {
4669                        $this->User->clear();
4670                        $updateCCArr = array('card_company' => $card_company);
4671
4672                        //Update also child card exp date same with parent
4673                        if (isset($ptPaymentParams['cardExpirationDate'])) {
4674                            $updateCCArr['card_expiration_date'] = $ptPaymentParams['cardExpirationDate'];
4675                        }
4676
4677                        if (!$this->User->read(array_keys($updateCCArr), $childId)) {
4678                            $this->log(__METHOD__ . ' child id does not exist. ' . json_encode($updateCCArr) . ' parent id --> ' . json_encode($userId), $logFileName);
4679                            $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'child id does not exist.', $updateCCArr);
4680                            return ;
4681                        }
4682
4683                        $this->User->set($updateCCArr);
4684                        if (!$this->User->save()) {
4685                            $this->log(__METHOD__ . ' failed to update child card company. ' . json_encode($updateCCArr) . ' parent id --> ' . json_encode($userId), $logFileName);
4686                            $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'failed to update child card company.', $updateCCArr);
4687                            return ;
4688                        }
4689                    }
4690                }
4691            }
4692
4693            // if light plan
4694            if ($formType == Configure::read('payment_lite_plan_upgrade') && $_allowChangePlan) {
4695                // check if user subscribed to zero student discount option
4696                $discountOptionData = $this->UserDiscountOptionsTerm->getTerm([
4697                    'user_id' =>  $userId,
4698                    'discount_option_id' => Configure::read('discount_option.zero_student.plan_id'),
4699                    'status' => 1
4700                ]);
4701
4702                // stop discount option
4703                if ($discountOptionData) {
4704                    // count successful discount
4705                    $discountCount = $this->DiscountOptionsSettlementHistory->countSuccessfulDiscount($discountOptionData['discount_option_term_id']);
4706                    
4707                    // open tunnel
4708                    myTools::initializeApiTunnel(['DiscountOptionController']);
4709
4710                    // initialize controller
4711                    $doc = new DiscountOptionController();
4712
4713                    $doshStatus = $discountCount ?
4714                        Configure::read('discount_option.dosh_status.midterm_cancellation') :
4715                        Configure::read('discount_option.dosh_status.maturity_cancellation');
4716
4717                    $szsdoParams = [
4718                        'discountOptionId' => $discountOptionData['discount_option_id'],
4719                        'discountOptionPriceId' => $discountOptionData['discount_option_price_id'],
4720                        'termId' => $discountOptionData['discount_option_term_id'],
4721                        'cancellationFee' => 0,
4722                        'cancellationType' => Configure::read('discount_option.dosh_type.plan_change'),
4723                        'userData' => $userData['User'],
4724                        'fromController' => $this->request->params['controller'],
4725                        'fromAction' => $this->request->params['action'],
4726                        'doshStatus' => $doshStatus
4727                    ];
4728
4729                    // set data
4730                    $doc->params = $szsdoParams;
4731
4732                    // stop
4733                    $stopDiscountOption = json_decode($doc->stopDiscountOption(), true);
4734
4735                    if (isset($stopDiscountOption['error']) && $stopDiscountOption['error']) {
4736                        $this->log(__METHOD__ . 'failed to stop zero student discount option: '.json_encode($szsdoParams), 'family_plan');
4737                        $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'failed to stop zero student discount option.', $szsdoParams);
4738                        return ;
4739                    }
4740                }
4741            }
4742
4743            // if study abroad | ryugaku payment
4744            if ($formType == Configure::read('payment_study_abroad')) {
4745                $estimationID = $ptPaymentParams['estimationReuqestID'];
4746                $getEstimationData = $this->RyugakuAdminEstimateRequest->find('first', array(
4747                    'fields' => array(
4748                        'RyugakuAdminEstimateRequest.*',
4749                    ),
4750                    'conditions' => array(
4751                        'RyugakuAdminEstimateRequest.user_id' => $userId,
4752                        'RyugakuAdminEstimateRequest.id' => $estimationID
4753                    ),
4754                    'recursive' => -1
4755                ));
4756
4757                if ($getEstimationData['RyugakuAdminEstimateRequest']) {
4758                    $pricingFeeTypes = Configure::read('admin_request_pricing_fee_types');
4759                    $ordd = $data["ordd"];
4760                    $cm_code = '';
4761                    $response_text = json_encode($data);
4762            
4763                    // save payment data
4764                    $rygakuPaymentData = array();
4765
4766                    // NJ-57361: get estimate request pricings
4767                    $adminEstimateRequestPricings = $this->RyugakuAdminEstimateRequestPricing->getAllRequestPricings($getEstimationData['RyugakuAdminEstimateRequest']['id'], false);
4768                    
4769                    foreach ($adminEstimateRequestPricings as $pricing) {
4770                        $pricing = $pricing['RyugakuAdminEstimateRequestPricing'];
4771                        
4772                        // - set value for amount
4773                        $amount = 0;
4774                        if ($pricing['type'] == $pricingFeeTypes['normal']) {
4775                            $amount = $pricing['fee'];
4776                        } else if ($pricing['type'] == $pricingFeeTypes['special']) {
4777                            $amount = $pricing['special_fee'];
4778                        }
4779
4780                        if ($pricing['taxable_flg']) {
4781                            $amount = $amount * Configure::read('tax.increase');
4782                        }
4783
4784                        if ($amount > 0) {
4785                            $rygakuPaymentData[] = [
4786                                'user_id' => $userId,
4787                                'estimation_request_id' => $estimationID,
4788                                'estimation_request_pricing_id' => $pricing['id'],
4789                                'user_payment_id' => $paymentSaveID,
4790                                'fee_type' => 0,
4791                                'currency_code' => Configure::read('default.user_currency'),
4792                                'amount' => $amount,
4793                                'ordd' => $ordd,
4794                                'cm_code' => $cm_code,
4795                                'response_text' => $response_text,
4796                                'payment_method' => 1 // phase 1
4797                            ];
4798                        }
4799                    }
4800
4801                    // save many to RyugakuSchoolPayment
4802                    $this->RyugakuSchoolPayment->saveMany($rygakuPaymentData);
4803
4804                    // update payment id
4805                    $this->RyugakuAdminEstimateRequest->updateAll(
4806                        array('RyugakuAdminEstimateRequest.payment_id' => $paymentSaveID),
4807                        array('RyugakuAdminEstimateRequest.id' => $estimationID)
4808                    );
4809                }
4810
4811
4812            }
4813
4814            $ptStatus = 1; // success
4815
4816
4817            // - NJ-31307 : trigger campaign
4818            if(!empty($ptPaymentParams['nativeOptionPayment']) || !empty($ptPaymentParams['callanOptionPayment'])){
4819                ClassRegistry::init('CampaignSettingTable')->callanUnlimitedCampaign(array(
4820                    'user_id' => $userId, 
4821                    'trigger' => 3, 
4822                    'pt_params' => $ptData ?? [],
4823                    'payment_type' => 'Zeuspay'
4824                ));
4825            }
4826
4827            // ~ NJ-65811: Logger
4828            if(
4829                $formType == Configure::read('payment_credit_change')
4830                && !empty($ptPassword)
4831                && (int) $monthlyPayment > 0
4832            ){
4833                $creditChangeCacheKey = "credit_change_{$userId}_{$ptPassword}";
4834                $creditChangeCache = $this->memcache->get($creditChangeCacheKey);
4835
4836                if(!$creditChangeCache){
4837                    $this->memcache->set(array(
4838                        'key' => $creditChangeCacheKey,
4839                        'value' => 1,
4840                        'expire' => 3600 // 1 hour
4841                    ));
4842                } else {
4843                    $mySlack = new mySlack();
4844                    $mySlack->channel = myTools::checkChannel("#nc-settlement", "#nc-settlement-dev");
4845                    $mySlack->username = "ZEUS CREDIT CHANGE REPORT";
4846                    $mySlack->text = "```";
4847                    $mySlack->text .= "DUPLICATE RECORD\n\n";
4848                    $mySlack->text .= "PAYMENT TRANSACTION PASSWORD:\n";
4849                    $mySlack->text .= $ptPassword . "\n\n";
4850                    $mySlack->text .= "METHOD\n";
4851                    $mySlack->text .=  __METHOD__ . "\n\n";
4852                    $mySlack->text .= "USER ID:\n";
4853                    $mySlack->text .= $userId . "\n\n";
4854                    $mySlack->text .= "KICKBACK URL:\n";
4855                    $mySlack->text .= $_SERVER['REQUEST_URI'] . "\n\n";
4856                    $mySlack->text .= "EC2 INSTANCE ID:\n";
4857                    $mySlack->text .= exec('ec2-metadata -i') . "\n\n";
4858                    $mySlack->text .= "DATA:\n";
4859                    $mySlack->text .= json_encode($data) . "\n";
4860                    $mySlack->text .= "```";
4861
4862                    try {
4863                        $mySlack->postMessage();
4864                        $this->log(__METHOD__ . ' ZEUS CREDIT CHANGE REPORT : DUPLICATE RECORD ->' . json_encode(["pt_password" => $ptPassword, "data" => $data]) , 'error');
4865                    } catch (Exception $e) {
4866                        CakeLog::write('debug', 'Error sending message: ' . $e->getMessage());    
4867                    }
4868                }
4869                
4870            }
4871
4872
4873        } else {
4874            $changePlanChargeFlg = $ptPaymentParams['changePlanChargeFlg'] ?? false;
4875            # possible fail transactions
4876            $inViableFailTransactions = array(
4877                Configure::read('payment_credit_monthly_payment'),
4878                Configure::read('payment_credit_coin_purchase'),
4879                Configure::read('payment_credit_receivable'),
4880                Configure::read('payment_credit_family_monthly_payment'),
4881                Configure::read('payment_native_option_join'),
4882                Configure::read('payment_native_option_monthly_payment'),
4883                Configure::read('payment_callan_option_join'),
4884                Configure::read('payment_callan_option_monthly_payment'),
4885                Configure::read('payment_lite_credit_monthly_payment'),
4886                Configure::read('payment_credit_chocotto_monthly_payment')
4887            );
4888
4889            # if the form type is a possible fail transaction
4890            if (in_array($formType, $inViableFailTransactions)) {
4891                // return if existing user or new user failed to become family plan paid user
4892                if (
4893                    $formType == Configure::read('payment_credit_family_monthly_payment') && $familyId &&
4894                    isset($ptPaymentParams['new_family_plan']) && $ptPaymentParams['new_family_plan']
4895                ) {
4896                    $this->log(__METHOD__ . 'zeus.error.ng_return_applying_family: '.json_encode($data), 'family_plan');
4897                    $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'failed to update child card company.', $updateCCArr);
4898                    return ;
4899                }
4900
4901                // - save user change membership status
4902                if (Configure::read('payment_credit_monthly_payment') == $formType) {
4903
4904                    $userTable = new UserTable($userData['User']);
4905                    $membershipTypes = UserTable::getEngMembershipTypeData();
4906                    $membershipTypeIndex = $userTable->getMembershipTypeIndex();
4907                    $tipAmount = null;
4908                    $parentId = $userTable->parent_id;
4909                    $is_cron = 0;
4910                    if ($ptPaymentParams['logFileName'] == 'monthly_payment'){
4911                        $is_cron = 1;
4912                    } 
4913
4914                       $currency_after = $userTable->currency_code;
4915                       
4916                       $plan_before = $ptPaymentParams['paymentPlanId'];
4917                    $plan_after = $userTable->payment_plan_id;
4918
4919                    $appreciationFlg = 0;
4920                    $tipAmount = null;
4921                    if (isset($ptPaymentParams['family_data']['applyPlan']['tip_max_amount']) && $ptPaymentParams['family_data']['applyPlan']['tip_max_amount']) {
4922                        $tipAmount = $ptPaymentParams['family_data']['applyPlan']['tip_max_amount'];
4923                    }
4924                    if (isset($ptPaymentParams['family_data']['applyPlan']['allow_appreciation_flg']) && $ptPaymentParams['family_data']['applyPlan']['allow_appreciation_flg'] && $tipAmount) {
4925                        $appreciationFlg = 1;
4926                    }
4927
4928                    $usclData = array(
4929                        'user_id' => $userId,
4930                        'platform' => $userTable->platform ?? '',
4931                        'card_company_before' => $userTable->card_company,
4932                        'status_before' => $membershipTypes[$membershipTypeIndex],
4933                        'status_after' => $membershipTypes[5],
4934                        'controller_name' => $this->request->params['controller'],
4935                        'action_name' => $this->request->params['action'],
4936                        'parent_id' => $parentId,
4937                        'is_cron' => $is_cron,
4938                        'currency_before' => $ptPaymentParams['currencyCode'],
4939                        'currency_after' => $currency_after,
4940                        'payment_plan_id_before' => $plan_before,
4941                        'payment_plan_id_after' => $plan_after,
4942                        'default_appreciation_flg' => $appreciationFlg,
4943                        'default_appreciation_amount' => $tipAmount
4944                    );
4945                    // save user change membership status
4946                    if (!$this->UserStatusChangeLog->saveLog($usclData)) {
4947                        $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'Unable to update status change log', $usclData);
4948                        return;
4949                    }
4950                }
4951
4952                # if form_type is for monthly payment
4953                if (
4954                    (
4955                        Configure::read('payment_credit_monthly_payment') == $formType ||
4956                        Configure::read('payment_credit_family_monthly_payment') == $formType ||
4957                        Configure::read('payment_lite_credit_monthly_payment') == $formType ||
4958                        Configure::read('payment_credit_chocotto_monthly_payment') == $formType
4959                    ) && !$changePlanChargeFlg
4960                ) {
4961                    # set user data
4962                    $this->User->validate = array();
4963                    $userPrevData = $this->User->read(null, $userData['User']['id']);
4964                    if (!$userPrevData) {
4965                        $this->log(__METHOD__ . ' User id does not exist. ' . json_encode($userData), $logFileName);
4966                        $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'User id does not exist', $userData);
4967                        return ;
4968                    }
4969
4970                    //update user memo && native option cancellation time
4971                    $date = date('Y/m/d H:i:s');
4972                    $memoStr = '';
4973                    $memoStr2 = '';
4974                    
4975                    // check if user is subscribed to native option and callan option
4976                    if(isset($userPrevData['User']['native_option']) && $userPrevData['User']['native_option']) { 
4977                        $memoStr = $date." Cancellation of Native Speaker Unlimited option";
4978                    }
4979
4980                    if(isset($userPrevData['User']['callan_option']) && $userPrevData['User']['callan_option']) {
4981                        $memoStr2 = $date." Cancellation of Callan Unlimited option";
4982                    }
4983
4984                    $updatedMemo = $memoStr."\n".$memoStr2."\n".$userPrevData['User']['memo'];
4985                    $userUpdate = array(
4986                        'fail_flg' => '1',
4987                        'counseling_attended_flg' => '1',
4988                        'charge_flg' => '0',
4989                        'allow_appreciation_flg' => '0',
4990                        'show_appreciation_flg' => '0',
4991                        'native_option' => 0,
4992                        'callan_option' => 0,
4993                        'next_charge_date' => NULL,
4994                        'memo' => $updatedMemo
4995                    );
4996
4997                    if (isset($userPrevData['User']['native_option']) && $userPrevData['User']['native_option']) {
4998                        $userUpdate['native_option_cancellation_time'] = $date;
4999                    }
5000
5001                    if (isset($userPrevData['User']['callan_option']) && $userPrevData['User']['callan_option']) {
5002                        $userUpdate['callan_option_cancellation_time'] = $date;
5003                    }
5004
5005                    $this->User->set($userUpdate);
5006                    if (!$this->User->save()) {
5007                        $this->log(__METHOD__ . ' Failed to update user data. ' . json_encode($userUpdate), $logFileName);
5008                        $this->slackZeusErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed to update user data', $userUpdate);
5009                        return ;
5010                    } else {
5011                        // check if has Native Option
5012                        if (isset($ptPaymentParams['nativeOptionPayment']) && $ptPaymentParams['nativeOptionPayment'] > 0) {
5013                            //NJ-2814 add logs
5014                            if (isset($ptPaymentParams['nativeOptionJoin']) && $ptPaymentParams['nativeOptionJoin']) {
5015                                $nativeStatus = 1; // subscribed
5016                                $statusBefore = $option_before_name = '';
5017                            } else {
5018                                $nativeStatus = 3; // unsubscribed
5019                                $statusBefore = 1;
5020                                $option_before_name = 'Native Unlimited Option';
5021                            }
5022
5023                            $optionLogParams = array(
5024                                'user_id' => $userId,
5025                                'platform' => $ptPaymentParams['platform'],
5026                                'status' => $nativeStatus,
5027                                'controller_name' => $this->request->params['controller'],
5028                                'action_name' => $this->request->params['action'],
5029                                'user_type' => 0, // user
5030                                'option_before' => $statusBefore,
5031                                'option_after' => 1,
5032                                'option_before_name' => $option_before_name,
5033                                'option_after_name' => '',
5034                                'option_type' => 1,
5035                                'payment_plan_id' => $paymentPlanId
5036                            );
5037
5038                            ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
5039                        }
5040
5041                        // check if has Callan Option
5042                        if (isset($ptPaymentParams['callanOptionPayment']) && $ptPaymentParams['callanOptionPayment'] > 0) {
5043                            //NJ-2814 add logs
5044                            if (isset($ptPaymentParams['callanOptionJoin']) && $ptPaymentParams['callanOptionJoin']) {
5045                                $callanStatus = 1; // subscribed
5046                                $statusBefore = $option_before_name = '';
5047                            } else {
5048                                $callanStatus = 3; // unsubscribed
5049                                $statusBefore = 1;
5050                                $option_before_name = 'Callan Unlimited Option';
5051                            }
5052
5053                            $optionLogParams = array(
5054                                'user_id' => $userId,
5055                                'platform' => $ptPaymentParams['platform'],
5056                                'status' => $callanStatus,
5057                                'controller_name' => $this->request->params['controller'],
5058                                'action_name' => $this->request->params['action'],
5059                                'user_type' => 0, // user
5060                                'option_before' => $statusBefore,
5061                                'option_after' => 1,
5062                                'option_before_name' => $option_before_name,
5063                                'option_after_name' => '',
5064                                'option_type' => 2,
5065                                'payment_plan_id' => $paymentPlanId
5066                            );
5067
5068                            ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
5069                        }
5070                    }
5071
5072                    # update user who join in ContinuationCampaign to fail status - 3
5073                    $this->ContinuationCampaign->setFailedUser(array(
5074                        'user_id' => $userData['User']['id']
5075                    ));
5076                    
5077                    // NJ-47740
5078                    // confiscate pending request coupon for native and callan option
5079                    $this->UsersCouponV1->confiscateOptionDiscount(array('userId' => $userId));
5080
5081                    // Get children list
5082                    $childList = $this->User->getChildId($userData['User']['id']);
5083
5084                    // check if user is parent 
5085                    if (!empty($childList)) {
5086                        foreach ($childList as $childId) {
5087                            // get child detail
5088                            $familyMember = $this->User->find('first', array(
5089                                'fields' => array(
5090                                    'User.id',
5091                                    'User.memo',
5092                                    'User.parent_id',
5093                                    'User.native_option',
5094                                    'User.callan_option'
5095                                ),
5096                                'conditions' => array('User.id' => $childId)
5097                            ));
5098                            $familyObj = new UserTable($familyMember['User']);
5099                            $addMemo = 'Family plan[User]: family deactivation parent failed settlement';
5100                            unset($familyObj->parent_id);
5101
5102                            // update children status to free
5103                            if ($this->User->updateStatusToFree($familyObj, $addMemo)) {
5104                                // - deactivate reserved lessons of the children
5105                                $this->LessonSchedule->deactivateDisableReservedLessons($childId, true, false, true, null, false, true);
5106
5107                                // NC-8645: add deactivation lock
5108                                UserTable::saveUserDeactivationLock($childId);
5109
5110                                // NC-5342: add deactivation log
5111                                $this->loadModel('FamilyDeactivationLog');
5112                                $this->FamilyDeactivationLog->addLog($childId);
5113                            }
5114                            
5115                            // NJ-47740
5116                            // confiscate pending request coupon for native and callan option
5117                            $this->UsersCouponV1->confiscateOptionDiscount(array('userId' => $childId));
5118                        }
5119                    }
5120                }
5121
5122                # set error code
5123                $data['error_code'] = Configure::read('zeus.error.ng_return');
5124                if (!$this->_error_log_set($data, $ptPaymentParams)) {
5125                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, '_error_log_set failed', $data);
5126                    return ;
5127                }
5128            } else {
5129            }
5130
5131            if ($nativeOptionPayment > 0 && in_array($formType, array(Configure::read('payment_credit_monthly_payment'), Configure::read('payment_credit_family_monthly_payment')))) {
5132                $data['formType'] = Configure::read('payment_native_option_monthly_payment');
5133                $ptPaymentParams['paymentAmount'] = $nativeOptionPayment;
5134
5135                if (!$this->_error_log_set($data, $ptPaymentParams)) {
5136                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, '_error_log_set failed', $data);
5137                    return ;
5138                }
5139            }
5140
5141            if ($callanOptionPayment > 0 && in_array($formType, array(Configure::read('payment_credit_monthly_payment'), Configure::read('payment_credit_family_monthly_payment')))) {
5142                $data['formType'] = Configure::read('payment_callan_option_monthly_payment');
5143                $ptPaymentParams['paymentAmount'] = $callanOptionPayment;
5144
5145                if (!$this->_error_log_set($data, $ptPaymentParams)) {
5146                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, '_error_log_set failed', $data);
5147                    return ;
5148                }
5149            }
5150
5151            if (isset($ptPaymentParams['annualDiscountOption']) && $formType == Configure::read('payment_halfway_termination_of_annual_discount_option')) {
5152                if (!$this->_error_log_set($data, $ptPaymentParams)) {
5153                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, '_error_log_set failed', $data);
5154                    return ;
5155                }
5156            }
5157
5158            if ($formType != Configure::read('payment_credit_authentication')) {
5159                $ptStatus = 2; // error;
5160            } else {
5161                $ptStatus = 0;
5162            }
5163        }
5164
5165        // update payment transaction
5166        $this->updatePaymentTransaction(array(
5167            'id' => $ptId,
5168            'fields' => array(
5169                'status' => $ptStatus,
5170                'response_text' => array('zp_kickback' => $data)
5171            ),
5172            'logFileName' => $logFileName
5173        ));
5174
5175        // add registration bonus if user registration
5176        if (isset($ptPaymentParams['userRegister']) && $ptPaymentParams['userRegister']) {
5177            
5178            if (
5179                isset($zeroStudentDiscount) && $zeroStudentDiscount &&
5180                $formType != Configure::read('payment_credit_chocotto_free') &&
5181                $formType != Configure::read('payment_credit_chocotto_monthly_payment') &&
5182                $formType != Configure::read('payment_credit_chocotto_retry') &&
5183                $formType != Configure::read('payment_credit_chocotto_force_charge')
5184            ) {
5185                UsersPointHistoryTable::checkDailyBonus($userId, true);
5186            } else {
5187                UsersPointHistoryTable::checkDailyBonus($userId);
5188            }
5189
5190            if (
5191                (isset($ptPaymentParams['campaign95percentOff']) && $ptPaymentParams['campaign95percentOff'])
5192                || (time() >= strtotime(Configure::read('campaign_config.feb_new_registration.period.start')) && time() <= strtotime(Configure::read('campaign_config.feb_new_registration.period.end')))
5193            ) {
5194                $paramsRefBonus = array(
5195                    "type" => 1, // kickback
5196                    "userID" => $userId,
5197                    "userRegister" => true
5198                );
5199                // add referral coin NC-10009
5200                $this->User->addReferralBonus($paramsRefBonus);
5201            }
5202
5203            // - check if lite plan user 
5204            $this->User->clear();
5205            $_currentUser = $this->User->read(array('id','memo','payment_plan_id'), $userId);
5206            $_currentUserMemo = $_currentUser['User']['memo'];
5207
5208            if (in_array($_currentUser['User']['payment_plan_id'], Configure::read('lite_payment_plans'))) {
5209                # update user memo
5210                $_coins = Configure::read('credit.lite_plan_bonus_coin_authentication');
5211                if ($formType == Configure::read('payment_lite_credit_monthly_payment')) {
5212                    $_coins = Configure::read('lite_plan_monthly_coin');
5213                }
5214                $_dateNow = date('Y-m-d H:i:s');
5215                $_updateMemo =  "\n {$_dateNow} Light Plan Bonus: {$_coins}";
5216                $_updateMemo = $_updateMemo . "\n" . $_currentUserMemo;
5217
5218                // - update user memo 
5219                $this->User->clear();
5220                $memUpdateParams = array(
5221                    'id' => $userId,
5222                    'memo' => $_updateMemo
5223                );
5224                $this->User->set($memUpdateParams);
5225                $this->User->save();
5226            }
5227        }
5228
5229
5230        // campaign master trigger 5 
5231        if (strtoupper($data['result']) == 'OK') {
5232            $this->retrial_confiscate_coins([
5233                'formType' => $formType,
5234                'paymentPlanId' => $paymentPlanId,
5235                'userId' => $userId
5236            ]);
5237        }
5238
5239        // - NJ-18780 : lite plan
5240        // Check if the payment result is successful and meets specific conditions for Lite monthly credit payment
5241        if (
5242            strtoupper($data['result']) == 'OK' &&
5243            $formType == Configure::read('payment_lite_credit_monthly_payment') && 
5244            in_array($userData['User']['payment_plan_id'], Configure::read('lite_payment_plans')) && // User must be on a Lite payment plan
5245            (!isset($ptPaymentParams['userRegister']) || !$ptPaymentParams['userRegister']) // Exclude cases where this is a user registration process
5246        ) {
5247            // confisacate and give monthly coin
5248
5249                // - fetch users mc coins
5250                $_monthlyPoints = $this->UsersPoint->getCurrentUserMCPoint($userId); //  mc coins
5251                $_dateNow = date('Y-m-d H:i:s');
5252                $_updateMemo = "";
5253
5254                if ((int) $_monthlyPoints > 0) {
5255                    $_confiscateParams = array(
5256                        'userId' => $userId,
5257                        'point' => $_monthlyPoints,
5258                        'kbn' => 18, // Administrator Change/Minus
5259                        'coinType' => 3
5260                    );
5261
5262                    $conficateLitePoints = $this->UsersPoint->confiscateUserLitePoints($_confiscateParams);
5263
5264                    if ($conficateLitePoints) {
5265                        $_updateMemo = $_updateMemo . "\n {$_dateNow} (Previous Coins (MC)【Confiscated】 : {$_monthlyPoints}. )";
5266                    }
5267                }
5268
5269                $_doneConfiscatePoints = ClassRegistry::init('UsersPointHistory')->confiscateUserLitePointsCoinBox($userId);
5270
5271                // update user memo 
5272                $_currentUser = $this->User->read(array('id','memo','next_charge_date'), $userId);
5273                $_nxtChargeDate = $_currentUser['User']['next_charge_date'];
5274                    
5275                // - set to add monthly coin
5276                $_pointParams = array(
5277                    'userId' => $userId,
5278                    'point' => Configure::read('lite_plan_monthly_coin'),
5279                    'kbn' => Configure::read('lite_plan_bonus_kbn'), // 
5280                    'kbnType' => 1, // add coin
5281                    'coinType' => 3, // mc coin
5282                    'dateExpiration' => $_nxtChargeDate,
5283                    'coinFailMessage' => Configure::read('coin.failed.membership')
5284                );
5285            
5286                // add user's points 
5287                $giveLitePoints = $this->UsersPoint->performPointTransaction($_pointParams);
5288
5289                if ($giveLitePoints) {
5290                    $_coins = Configure::read('lite_plan_monthly_coin');
5291                    $_updateMemo = $_updateMemo . "\n {$_dateNow} | Light Plan Bonus Coins (MC): {$_coins}";
5292                }
5293
5294        
5295                $_currentUserMemo = $_currentUser['User']['memo'];
5296
5297                if (!empty($_updateMemo)) {
5298                    $_updateMemo = $_updateMemo . "\n" . $_currentUserMemo;
5299                    $this->User->clear();
5300                    $this->User->set(array('id' => $userId,'memo' => $_currentUserMemo));
5301                    $this->User->save();
5302                }
5303        }
5304
5305        // send event to adjust
5306        if ($kbResult) {
5307            $adjustParams = array(
5308                'formType' => $formType,
5309                'statusBefore' => isset($ptPaymentParams['statusBefore']) ? $ptPaymentParams['statusBefore'] : null,
5310                'userId' => $userId,
5311                'idfa' => $userData['User']['idfa']
5312            );
5313            UserTable::sendEventToAdjust($adjustParams);
5314        }
5315
5316        //NJ-23626 continuing plan campaign
5317        if ((strtoupper($data['result']) == 'OK' || !empty($ptPaymentParams['coupon_used'])) && in_array($formType, array(Configure::read('payment_credit_retry'), Configure::read('payment_credit_monthly_payment')))){
5318            ClassRegistry::init('CampaignSettingTable')->takingLessonAndContinuePlan(array('user_id' => $userId, 'type' => 3));
5319        }
5320
5321        return ;
5322    } //end zeuspay()
5323
5324    private function saveStep($userId, $stepKey) {
5325        $sp = Configure::read('registration_platforms.sp');
5326        $pc = Configure::read('registration_platforms.pc');
5327        $platformId = $this->RequestHandler->isMobile() ? $sp : $pc;
5328
5329        $saveStepParams = array(
5330            'user_id' => $userId,
5331            'step_key' => $stepKey,
5332            'platform' => $platformId,
5333            'language' => $this->localizeDir
5334        );
5335
5336        ClassRegistry::init('UserRegistrationStatus')->saveStep($saveStepParams);
5337    }
5338    /**
5339     * @api {post} /payment/corporateZeuspay/:sendpoint/:result/:usingCompanyCard/:original_sendid/:sendid/:ordd/:money/:cardbrand/:cardnumber/:payment_id/:error_code/:formType/:user_id corporateZeuspay()
5340     * @apiName corporateZeuspay
5341     * @apiGroup Payment
5342     * @apiDescription This function is used to process corporate payment.
5343     * 
5344     * @apiParam {String} sendpoint payment hash
5345     * @apiParam {String} result result of payment
5346     * @apiParam {String} usingCompanyCard flag if using company card
5347     * @apiParam {String} original_sendid original send id
5348     * @apiParam {String} sendid send id of payment
5349     * @apiParam {String} ordd The order id
5350     * @apiParam {String} money The amount of money
5351     * @apiParam {String} cardbrand The card brand
5352     * @apiParam {String} cardnumber The card number
5353     * @apiParam {String} payment_id The payment id
5354     * @apiParam {String} error_code The error code for payment
5355     * @apiParam {String} formType The form type of payment
5356     * @apiParam {String} user_id The user id
5357     * 
5358     * @apiSuccess {Database} Save saves/update the payment data to database.
5359     * 
5360     * @apiError {PHP} log Logs the error if there is an error in the payment.
5361     * 
5362     * @apiSuccessExample Success Response Corporate admin payment transaction:
5363     * Save/update the payment data to corporate admin payment transaction table.
5364     * @apiSuccessExample Success Response Corporate payment receivable:
5365     * create payment transaction in corporates payment receivable table.
5366     *
5367     * @apiErrorExample Error Response:
5368     * logs the error if there is an error in the payment.
5369     * 
5370     * @apiSampleRequest off
5371     */
5372    public function corporateZeuspay($data) {
5373        $corporateUser = $corporateAdmin = false;
5374        $ptData = array();
5375        $paymentHash = trim($data['sendpoint']); // get payment hash
5376        $kbResultOk = strtoupper($data['result']) == 'OK' ? true : false;
5377        $usingCompanyCard = isset($data['usingCompanyCard']) ? $data['usingCompanyCard'] : false;
5378
5379        if ($usingCompanyCard) {
5380            $this->loadModel('CorporateAdminPaymentTransaction');
5381            $data['original_sendid'] = $data['sendid'];
5382            $data['sendid'] = str_replace('cz', '', $data['sendid']); // remove cz
5383
5384            // get transaction data from corporate admin payment transaction table
5385            if ($ptData =  $this->CorporateAdminPaymentTransaction->getPaymentTransaction(array('payment_hash' => $paymentHash))) {
5386                // return if status value is not 0
5387                if ($ptData['status'] != 0) {
5388                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $data['sendid'], 'Corporate admin payment transaction does not exist or status value is not equals to 0', $data);
5389                    return ;
5390                }
5391                $corporateAdmin = true;
5392            }
5393        }
5394
5395        // if empty $ptData
5396        if (empty($ptData)) {
5397            // get transaction data from payment transaction table
5398            $ptData = $this->PaymentTransaction->getWPPaymentTransaction($paymentHash);
5399
5400            // do nothing if payment transaction (payment hash and status = 0) does not exist.
5401            if (!$ptData) {
5402                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $data['sendid'], 'Payment transaction does not exist or status value is not equals to 0', $data);
5403                return ;
5404            }
5405            $corporateUser = true;
5406        }
5407
5408        if ($corporateAdmin) {
5409            $this->loadModel('CorporateAdminPayment');
5410
5411            $ptpp = json_decode($ptData['payment_params'], true); // decode corporate admin payment transaction payment_params to array
5412            $formType = isset($ptpp['formType']) ? $ptpp['formType'] : null;
5413            $cardExpirationDate = isset($ptpp['cardExpirationDate']) ? $ptpp['cardExpirationDate'] : null;
5414            $ordd = isset($data['ordd']) ? $data['ordd'] : null;
5415            $corporateId = $data['sendid'];
5416
5417            $monthlyPaymentExist = $this->CorporateAdminPayment->find('count', array(
5418                'conditions' => array(
5419                    'corporate_id' => $corporateId,
5420                    'ordd' => $ordd,
5421                    'form_type' => $formType
5422                )
5423            ));
5424
5425            // return if payment already exist
5426            if ($monthlyPaymentExist) {
5427                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $corporateId, 'Corporate admin payment data already exist.', $data);
5428                return ;
5429            }
5430
5431            $ptStatus = 1; // default status value
5432            $insertData = array(
5433                'corporate_id' => $corporateId,
5434                'form_type' => $formType,
5435                'ordd' => $ordd,
5436                'amount' => $data['money'],
5437                'param1' => json_encode($data)
5438            );
5439
5440            if ($kbResultOk) {
5441                if ($formType == Configure::read('payment_credit_authentication')) {
5442                    $updateData = array(
5443                        'card_brand' => $data['cardbrand'],
5444                        'card_number' => $data['cardnumber'],
5445                        'card_expiration_date' => $cardExpirationDate
5446                    );
5447
5448                    // update corporate admin card brand and card number
5449                    if (!$this->Corporate->updateData($updateData, $corporateId)) {
5450                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $corporateId, 'Failed to update corporate admin card brand and card number.', $data);
5451                        return ;
5452                    }
5453                }
5454            } else {
5455                $ptStatus = 2;
5456                $insertData['param2'] = 'error:' . $data['error_code'];
5457            }
5458
5459            // insert corporate admin payment
5460            if (!$this->CorporateAdminPayment->saveData($insertData)) {
5461                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $corporateId, 'Failed to save corporate admin payment data.', $data);
5462                return ;
5463            }
5464
5465            // update corporate admin payment transaction
5466            $responseText = array();
5467            $updateData = array('status' => $ptStatus, 'response_text' => '');
5468            $this->CorporateAdminPaymentTransaction->clear();
5469            $read = $this->CorporateAdminPaymentTransaction->read(array_keys($updateData), $ptData['id']);
5470            $rtArr = !empty($read['CorporateAdminPaymentTransaction']['response_text']) ? json_decode($read['CorporateAdminPaymentTransaction']['response_text'], true) : array();
5471
5472            array_push($responseText, $rtArr, $data);
5473            $updateData['response_text'] = json_encode($responseText);
5474            $this->CorporateAdminPaymentTransaction->set($updateData);
5475            if (!$this->CorporateAdminPaymentTransaction->save()) {
5476                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $corporateId, 'Failed to update corporate payment transaction.', $data);
5477                return;
5478            }
5479
5480            return;
5481        } elseif ($corporateUser) {
5482            $ptpp = json_decode($ptData['payment_params'], true); // decode payment transaction payment_params to array
5483            $formType = isset($ptpp['formType']) ? $ptpp['formType'] : null;
5484            $logFileName = isset($ptpp['logFileName']) && !empty($ptpp['logFileName']) ? $ptpp['logFileName'] : 'debug';
5485            $paymentPlanId = isset($ptpp['paymentPlanId']) ? $ptpp['paymentPlanId'] : null;
5486            $priceId = isset($ptpp['priceId']) ? $ptpp['priceId'] : null;
5487            $cronDateRun = isset($ptpp['cronDateRun']) ? $ptpp['cronDateRun'] : date('Y-m-d H:i:s');
5488            // Override if form type is corporate credit card registration
5489
5490            if (
5491                (
5492                    $formType == Configure::read('corporate_credit_card_registration') ||
5493                    $formType == Configure::read('payment_credit_change')
5494                ) 
5495                &&
5496                isset($ptData['created'])
5497            ) {
5498                $cronDateRun = $ptData['created'];
5499            }
5500
5501            $cardExpirationDate = isset($ptpp['cardExpirationDate']) ? $ptpp['cardExpirationDate'] : null;
5502            $amount = isset($data['money']) ? $data['money'] : 0;
5503            $receivablePayment = $appreciationReceivable = $liveLessonReceivable = 0;
5504            $discounted_amount = isset($ptpp['discounted_amount']) ? $ptpp['discounted_amount'] : 0;
5505            $currencyCode = isset($ptpp['currencyCode']) ? $ptpp['currencyCode'] : Configure::read('currency_jpy');
5506
5507            if (!isset($ptpp['corporateSettlementType']) && $formType != Configure::read('payment_credit_change')) {
5508                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $ptData['user_id'], 'Parameter corporate settlement type is missing.', $data);
5509                return ;
5510            }
5511
5512            $settlementType = $ptpp['corporateSettlementType'];
5513            $settlementTypes = Configure::read('corporate_settlement_types');
5514            $userId = $ptData['user_id'];
5515            $cardCompany = Configure::read('card_company.zeus');
5516
5517            // get user data
5518            $userData = $this->User->find('first', array(
5519                'fields' => array(
5520                    'User.*',
5521                    'Corporate.*'
5522                ),
5523                'joins' => array(
5524                    array(
5525                        'table' => 'corporates',
5526                        'alias' => 'Corporate',
5527                        'type' => 'LEFT',
5528                        'conditions' => 'Corporate.id = User.corporate_id'
5529                    )
5530                ),
5531                'conditions' =>array('User.id' => $userId),
5532                'recursive' => -1
5533            ));
5534
5535            $corporateData = $userData['Corporate'];
5536            $membershipStatusIndex = UserTable::getStudentMembershipStatus($userId);
5537            $userData = $userData['User'];
5538            $corpType = $paymentPlanId ? myTools::getCoporateTypeUsingPaymentPlanId($paymentPlanId) : myTools::getCoporateTypeUsingPaymentPlanId($userData['payment_plan_id']);
5539            $corporateId = isset($ptpp['corporateId']) ? $ptpp['corporateId'] : $userData['corporate_id'];
5540
5541            // - add corp type base on user's selected plan
5542            if ($paymentPlanId) {
5543                $userData['corporate_type'] = $paymentPlanId ? myTools::getCoporateTypeUsingPaymentPlanId($paymentPlanId) : myTools::getCoporateTypeUsingPaymentPlanId($userData['payment_plan_id']);
5544                $corpType = $paymentPlanId ? myTools::getCoporateTypeUsingPaymentPlanId($paymentPlanId) : myTools::getCoporateTypeUsingPaymentPlanId($userData['payment_plan_id']);
5545            }
5546
5547            $corpTypeStandard = Configure::read('corporate_type.standard');
5548            $corpTypePremium = Configure::read('corporate_type.premium');
5549            $corpTypeLight = Configure::read('corporate_type.light');
5550
5551            // - NJ-23781 update users_detail.individual_card_fail_flg
5552            $updateIndividualCardFlgParams = [
5553                'user_data' => $userData,
5554                'form_type' => $formType,
5555                'individual_card_fail_flg' => 1, // 0: success, 1: fail
5556            ];
5557
5558            // NC-8194: check null payment_plan_id and price_id
5559            if (!$paymentPlanId || !$priceId) {
5560                if ($userData['payment_plan_id'] && $userData['price_id']) {
5561                    $paymentPlanId = $userData['payment_plan_id'];
5562                    $priceId = $userData['price_id'];
5563                } else {
5564                    $defPlan = $this->PaymentPlanPrice->getDefaultPlan($userData);
5565                    $paymentPlanId = $defPlan['paymentPlanId'];
5566                    $priceId = $defPlan['priceId'];
5567                }
5568            }
5569
5570            // if standard or premium individual plan user and
5571            if (in_array($corpType, array($corpTypePremium, $corpTypeStandard, $corpTypeLight))) {
5572                if (
5573                    in_array($formType, array(
5574                        Configure::read('payment_credit_receivable'),
5575                        Configure::read('payment_individual_corporate_standard'),
5576                        Configure::read('payment_individual_corporate_premium'),
5577                        Configure::read('payment_prepaid_corporate_light_member'),
5578                        Configure::read('payment_credit_change'),
5579                        Configure::read('corporate_credit_card_registration')
5580                    ))
5581                ) {
5582                    // get receivable reservation payment
5583                    $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun);
5584
5585                    if ($receivablePayment && $receivablePayment <= $amount) {
5586                        $ptpp['paymentAmount'] = $amount -= $receivablePayment;
5587                    }
5588
5589                    // get appreciation receivable payments
5590                    $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('appreciation_data.payment_element_type'));
5591
5592                    if ($appreciationReceivable && $appreciationReceivable <= $amount) {
5593                        $ptpp['paymentAmount'] = $amount -= $appreciationReceivable;
5594                    }
5595
5596                    // get live receivable payments
5597                    $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.live'));
5598
5599                    if ($liveLessonReceivable && $liveLessonReceivable <= $amount) {
5600                        $ptpp['paymentAmount'] = $amount -= $liveLessonReceivable;
5601                    }
5602                }
5603            }
5604
5605            $nativeOptionPayment = 0;
5606            $callanOptionPayment = 0;
5607
5608            // if has native speaker payments
5609            // deduct
5610            if (isset($ptpp['nativeOptionPayment']) && $ptpp['nativeOptionPayment'] > 0 && $formType != Configure::read('payment_native_option_join')) {
5611                $nativeOptionPayment = $ptpp['nativeOptionPayment']; // - native option payment
5612                $ptpp['paymentAmount'] = $amount -= $nativeOptionPayment;
5613            }
5614
5615            // if has callan option payment
5616            if (isset($ptpp['callanOptionPayment']) && $ptpp['callanOptionPayment'] > 0 && $formType != Configure::read('payment_callan_option_join')) {
5617                $callanOptionPayment = $ptpp['callanOptionPayment']; // - callan option payment
5618                $ptpp['paymentAmount'] = $amount -= $callanOptionPayment;
5619            }
5620
5621            // set transaction
5622
5623            if ($kbResultOk) {
5624                $ptPassword = isset($ptData['password']) ? $ptData['password'] : null;
5625                $paymentType = isset($ptpp['paymentType']) ? $ptpp['paymentType'] : null;
5626                $basicFee = isset($ptpp['basicFee']) ? $ptpp['basicFee'] : 0;
5627                $lessonFee = isset($ptpp['lessonFee']) ? $ptpp['lessonFee'] : 0;
5628                $ordd = isset($data['ordd']) ? $data['ordd'] : null;
5629
5630                $formTypeIndiLight = Configure::read('payment_prepaid_corporate_light_member');
5631                $formTypeIndiLightLesson = Configure::read('payment_prepaid_corporate_light_member_lesson');
5632                $formTypeComCardLightlLesson = Configure::read('payment_company_credit_corporate_light_lesson');
5633
5634                // corporate payment receivable types
5635                $cprTypes = array(
5636                    $corpTypeStandard => $this->CorporatesPaymentReceivable->typeCorporateStandard,
5637                    $corpTypePremium => $this->CorporatesPaymentReceivable->typeCorporatePremium,
5638                    $corpTypeLight => $this->CorporatesPaymentReceivable->typeCorporateLight
5639                );
5640
5641                /** -- >> START << insert or update corporate payment receivable -- **/
5642
5643                if ($formType != $formTypeIndiLight) {
5644                    // user registration or re-enroll
5645                    if (
5646                        in_array($settlementType, array($settlementTypes['card_registration'], $settlementTypes['force_charge_payment'])) &&
5647                        isset($ptpp['addCorporateReceivable'])
5648                    ) {
5649                        $addCPRData = $ptpp['addCorporateReceivable'];
5650                        $chargeFlg = $corporateData['payment_method'] == 1 ? 1 : 0;
5651                        // insert
5652                        if (isset($addCPRData['amount']) && isset($addCPRData['discount'])) {
5653                            $insertData = array(
5654                                'corporate_id' => $corporateId,
5655                                'user_id' => $userId,
5656                                'type' => isset($cprTypes[$corpType]) ? $cprTypes[$corpType] : 0,
5657                                'status' => 1, // paid
5658                                'quantity' => 1,
5659                                'amount' => $addCPRData['amount'],
5660                                'discount' => $addCPRData['discount'],
5661                                'next_settlement' => date('Y-m-d 00:00:00'),
5662                                'payment_collection_date' => date('Y-m-d H:i:s'),
5663                                'charge_flg' => $chargeFlg
5664                            );
5665
5666                            // create corporate payment receivable
5667                            $createSuccess = $this->CorporatesPaymentReceivable->addReceivablePayment($insertData);
5668
5669                            // rollback and return if failed to create payment receivable
5670                            if (!$createSuccess) {
5671                                $this->log(__METHOD__ . ' Failed to create payment receivable. --> ' . json_encode($insertData) . ' -- ' . json_encode($data), $logFileName);
5672                                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to create payment receivable.', $data);
5673                                return ;
5674                            }
5675                        }
5676
5677                        // insert lesson fee
5678                        if (isset($addCPRData['lessonFeeAmount']) && isset($addCPRData['lessonFeeQty'])) {
5679                            $insertData = array(
5680                                'corporate_id' => $corporateId,
5681                                'user_id' => $userId,
5682                                'type' => $this->CorporatesPaymentReceivable->typeCorporateLightLessonFee,
5683                                'status' => 1, // paid
5684                                'quantity' => $addCPRData['lessonFeeQty'],
5685                                'amount' => $addCPRData['lessonFeeAmount'],
5686                                'discount' => 0,
5687                                'next_settlement' => date('Y-m-d 00:00:00')
5688                            );
5689
5690                            // create corporate payment receivable for lesson fee
5691                            $createSuccess = $this->CorporatesPaymentReceivable->addReceivablePayment($insertData);
5692
5693                            // rollback and return if failed to create payment receivable for lesson fee
5694                            if (!$createSuccess) {
5695                                $this->log(__METHOD__ . ' Failed to create payment receivable for lesson fee. --> ' . json_encode($insertData) . ' -- ' . json_encode($data), $logFileName);
5696                                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to create payment receivable for lesson fee.', $data);
5697                                return ;
5698                            }
5699                        }
5700                    }
5701
5702                    // user withdrawn or monthly payment or monthly payment retry - lesson fee payment
5703                    if ($settlementType == $settlementTypes['lesson_fee_payment']) {
5704                        // insert
5705                        if (isset($ptpp['addCorporateReceivable'])) {
5706                            $addCPRData = $ptpp['addCorporateReceivable'];
5707
5708                            if (isset($addCPRData['lessonFeeAmount']) && isset($addCPRData['lessonFeeQty'])) {
5709                                $insertData = array(
5710                                    'corporate_id' => $corporateId,
5711                                    'user_id' => $userId,
5712                                    'type' => $this->CorporatesPaymentReceivable->typeCorporateLightLessonFee,
5713                                    'status' => 1, // paid
5714                                    'quantity' => $addCPRData['lessonFeeQty'],
5715                                    'amount' => $addCPRData['lessonFeeAmount'],
5716                                    'discount' => 0,
5717                                    'next_settlement' => date('Y-m-d 00:00:00')
5718                                );
5719
5720                                // create corporate payment receivable for lesson fee
5721                                $createSuccess = $this->CorporatesPaymentReceivable->addReceivablePayment($insertData);
5722
5723                                // rollback and return if failed to create payment receivable for lesson fee
5724                                if (!$createSuccess) {
5725                                    $this->log(__METHOD__ . ' Failed to create payment receivable for lesson fee. --> ' . json_encode($insertData) . ' -- ' . json_encode($data), $logFileName);
5726                                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to create payment receivable for lesson fee.', $data);
5727                                    return ;
5728                                }
5729                            }
5730                        }
5731
5732                        // update
5733                        if (isset($ptpp['updateCorporateReceivable'])) {
5734                            $cprParams = array(
5735                                'userId' => $userId,
5736                                'corporateId' => $userData['corporate_id'],
5737                                'type' => $this->CorporatesPaymentReceivable->typeCorporateLightLessonFee
5738                            );
5739
5740                            // update lesson fee status to paid
5741                            $updateSuccess = $this->CorporatesPaymentReceivable->updateReceivablePaymentToPaid($cprParams);
5742
5743                            // rollback and return if failed to update lesson fee status to paid
5744                            if (!$updateSuccess) {
5745                                $this->log(__METHOD__ . ' Failed to update payment lesson fee status to paid. --> ' . json_encode($data), $logFileName);
5746                                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update lesson fee status to paid.', $data);
5747                                return ;
5748                            }
5749                        }
5750                    }
5751
5752                    // monthly payment or monthly payment retry or payment retry or force charge payment
5753                    if (
5754                        (in_array(
5755                            $settlementType,
5756                            array(
5757                                $settlementTypes['monthly_payment'],
5758                                $settlementTypes['monthly_payment_retry'],
5759                                $settlementTypes['retry_payment'],
5760                                $settlementTypes['force_charge_payment']
5761                            )
5762                        ) || $formType == Configure::read('payment_credit_change')) && isset($ptpp['updateCorporateReceivable'])
5763                    ) {
5764                        $cprParams = array(
5765                            'userId' => $userId,
5766                            'corporateId' => $userData['corporate_id']
5767                        );
5768
5769                        // update payment receivable(s) status to paid (including lesson fee)
5770                        $updateSuccess = $this->CorporatesPaymentReceivable->updateReceivablePaymentToPaid($cprParams);
5771
5772                        // rollback and return if failed to update payment receivble(s) status to paid
5773                        if (!$updateSuccess) {
5774                            $this->log(__METHOD__ . ' Failed to update payment receivable(s) status to paid. --> ' . json_encode($data), $logFileName);
5775                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update payment receivable(s) status to paid.', $data);
5776                            return ;
5777                        }
5778                    }
5779
5780                    // corporate admin retry payment
5781                    if ($settlementType == $settlementTypes['retry_payment'] && isset($ptpp['companyCardRetryReceivableId'])) {
5782                        // update staus to paid
5783                        $updateSuccess = $this->CorporatesPaymentReceivable->updateReceivablePaymentToPaid(array('id' => $ptpp['companyCardRetryReceivableId']));
5784
5785                        // rollback and return if failed to update status to paid
5786                        if (!$updateSuccess) {
5787                            $this->log(__METHOD__ . ' Failed to update value to paid. --> ' . json_encode($data), $logFileName);
5788                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update status to paid.', $data);
5789                            return ;
5790                        }
5791
5792                        // udate corporate admin
5793                        if (isset($ptpp['updateCorporateAdminCardInfo'])) {
5794                            $updateData = array(
5795                                'card_brand' => $data['cardbrand'],
5796                                'card_number' => $data['cardnumber'],
5797                            );
5798
5799                            if (isset($cardExpirationDate)) {
5800                                $updateData['card_expiration_date'] = $cardExpirationDate;
5801                            }
5802
5803                            // update corporate admin card brand and card number
5804                            if (!$this->Corporate->updateData($updateData, $corporateId)) {
5805                                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update corporate admin card brand and card number.', $data);
5806                                return ;
5807                            }
5808                        }
5809                    }
5810                // individual light plan
5811                } else {
5812                    if (!in_array($settlementType, array($settlementTypes['card_registration'], $settlementTypes['lesson_fee_payment']))) {
5813                        // update status to paid
5814                        $updateSuccess = $this->CorporatePaymentMemberReceivable->updateReceivableStatus(array('user_id' => $userId));
5815
5816                        // rollback and return if failed to update status to paid
5817                        if (!$updateSuccess['result']) {
5818                            $this->log(__METHOD__ . ' Failed to update status to paid. --> ' . json_encode($data), $logFileName);
5819                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update status to paid.', $data);
5820                            return ;
5821                        }
5822                    }
5823                }
5824                /** -- >> END << insert or update corporate payment receivable -- **/
5825                $receivableFormTypeArr = array( 
5826                    Configure::read('payment_credit_receivable'),
5827                    Configure::read('payment_credit_appreciation_receivable'),
5828                    Configure::read('payment_live_lesson_receivable')
5829                );
5830
5831                $userData = $this->User->find('first', array(
5832                    'conditions' =>array('id' => $userId),
5833                    'recursive' => -1
5834                ));
5835
5836                $userData = $userData['User'];
5837                $currency_before_payment = $userData['currency_code'];
5838                $plan_id_before_payment = $userData['payment_plan_id'];
5839
5840                $paymentData = array(
5841                    'user_id' => $userId,
5842                    'amount' => $amount,
5843                    'status' => 1,
5844                    'reference_id' => $data['sendid'],
5845                    'payment_transaction_password' => $ptPassword,
5846                    'card_company' => $cardCompany,
5847                    'param1' => json_encode($data),
5848                    'form_type' => $formType,
5849                    'ordd' => $ordd,
5850                    'transaction_code' => $paymentHash,
5851                    'currency_id' => Configure::read('default.settlement_currency_id'), // set currency id to jpy
5852                    'currency_code' => $currencyCode,
5853                    'payment_id' => $paymentPlanId,
5854                    'price_id' => $priceId,
5855                    'payment_type' => $paymentType,
5856                    'discounted_amount' => $discounted_amount
5857                );
5858
5859                // - if not receivable payment
5860                if( !in_array( $formType, $receivableFormTypeArr ) ) {
5861                    // add basic fee and/or lesson fee if corporate light
5862                    if ($corpType == $corpTypeLight) {
5863                        if ($userData['corporate_last_charge_date']) {
5864                            $paymentData["lesson_fee_date_started"] = $userData['corporate_last_charge_date'];
5865                        }
5866
5867                        // basic fee
5868                        if ($formType == $formTypeIndiLight || $formType == Configure::read('payment_company_credit_corporate_light')) {
5869                            $paymentData['amount'] = $basicFee;
5870                            $paymentData['basic_fee'] = $basicFee;
5871                            $paymentData['lesson_fee'] = 0;
5872
5873                            // has lesson fee
5874                            if (isset($lessonFee) && $lessonFee > 0) {
5875                                $forLessonFee = $paymentData; // copy
5876                                $forLessonFee['amount'] = $lessonFee;
5877                                $forLessonFee['lesson_fee'] = $lessonFee;
5878                                $forLessonFee['basic_fee'] = 0;
5879
5880                                // change to lesson fee form type
5881                                if ($formType == $formTypeIndiLight) {
5882                                    $forLessonFee['form_type'] = $formTypeIndiLightLesson;
5883                                } else {
5884                                    $forLessonFee['form_type'] = $formTypeComCardLightlLesson;
5885                                }
5886
5887                                // create new payment for lesson fee
5888                                $this->Payment->clear();
5889                                $this->Payment->create();
5890                                $this->Payment->set($forLessonFee);
5891
5892                                // rollback if payment was not saved
5893                                if (!$this->Payment->save()) {
5894                                    $this->log(__METHOD__ . ' Failed to save light plan lesson fee payment. --> ' . json_encode($forLessonFee) . ' -- ' . json_encode($data), $logFileName);
5895                                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save light plan lesson fee payment.', $data);
5896                                    return ;
5897                                }
5898
5899                                //update/add user`s settlement amount
5900                                $this->User->updateUserPayments($paymentData);
5901                            }
5902                        } else {
5903                            if (isset($lessonFee) && $lessonFee > 0) {
5904                                $paymentData['lesson_fee'] = $lessonFee;
5905                            }
5906                        }
5907                    }
5908
5909                    // create new payment
5910                    $this->Payment->clear();
5911                    $this->Payment->create();
5912                    $this->Payment->set($paymentData);
5913
5914                    // rollback if payment was not saved
5915                    if (!$this->Payment->save()) {
5916                        $this->log(__METHOD__ . ' Failed to save payment data. --> ' . json_encode($paymentData) . ' -- ' . json_encode($data), $logFileName);
5917                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data.', $data);
5918                        return ;
5919                    }
5920
5921                    //update/add user`s settlement amount
5922                    $this->User->updateUserPayments($paymentData);
5923                }
5924
5925                // - process after payment logic
5926                if (
5927                    $formType != Configure::read('corporate_credit_card_registration') &&
5928                    $formType != Configure::read('payment_credit_textbook_purchase') &&
5929                    $formType != Configure::read('payment_credit_coin_purchase') &&
5930                    $formType != Configure::read('payment_prepaid_corporate_light_member_lesson') &&
5931                    $formType != Configure::read('payment_company_credit_corporate_light_lesson') &&
5932                    $formType != Configure::read('payment_credit_receivable') &&
5933                    $formType != Configure::read('payment_native_option_join') &&
5934                    $formType != Configure::read('payment_native_option_monthly_payment') &&
5935                    $formType != Configure::read('payment_callan_option_join') &&
5936                    $formType != Configure::read('payment_callan_option_monthly_payment') &&
5937                    $formType != Configure::read('payment_credit_appreciation_receivable') &&
5938                    isset($corporateId) && isset($corpType) &&
5939                    $settlementType != 'lesson_fee_payment'
5940                ) {
5941
5942                    $counselingAttendedFlg = $corpType == $corpTypeLight ? 1 : 0;
5943                    $datetime = date('Y-m-d H:i:s');
5944
5945                    $this->Corporate->openDBReplica();
5946                    $corporateSpeakingMustFlg = $this->Corporate->find('first', array(
5947                            'conditions' => array('Corporate.id' => $corporateId),
5948                            'fields' => 'Corporate.monthly_speaking_business_attended_must_flg'
5949                        )
5950                    );
5951                    $this->Corporate->closeDBReplica();
5952                    $monthlySpeakingBusinessAttendedMustFlg = $corporateSpeakingMustFlg['Corporate']['monthly_speaking_business_attended_must_flg'];
5953
5954
5955                    $saveUserArr = array(
5956                        'status' => 1,
5957                        'modified' => $datetime,
5958                        'fail_flg' => 0,
5959                        'charge_flg' => 1,
5960                        'counseling_attended_flg' => $counselingAttendedFlg,
5961                        'hash16' => $userId,
5962                        'last_charge_date' => $datetime,
5963                        'payment_plan_id' => $paymentPlanId,
5964                        'price_id' => $priceId,
5965                        'double_check_flg' => 0,
5966                        'expired_card_flg' => 0,
5967                        'sms_through_flg' => 1,
5968                        'corporate_type' => $corpType,
5969                        'monthly_speaking_business_attended_must_flg' => $monthlySpeakingBusinessAttendedMustFlg
5970                        // 'native_option' => 0,
5971                        // 'callan_option' => 0,
5972                        // 'unli_native_personal_card_flg' => 0,
5973                        // 'unli_callan_personal_card_flg' => 0
5974                    );
5975
5976                    if (!isset($userData['corporate_id']) || $userData['corporate_id'] != $corporateId) {
5977                        $saveUserArr['corporate_id'] = $corporateId;
5978                    }
5979
5980                    if (
5981                        $usingCompanyCard &&
5982                        !isset($userData['card_brand']) &&
5983                        !isset($userData['card_number'])
5984                    ) {
5985                        $saveUserArr['card_company'] = null;
5986                    } else {
5987                        $saveUserArr['card_company'] = $cardCompany;
5988                    }
5989
5990                    if (!$usingCompanyCard) {
5991                        $saveUserArr['card_number'] = $data['cardnumber'];
5992                        $saveUserArr['card_brand'] = $data['cardbrand'];
5993                    }
5994
5995                    // if form type prepaid coporate light
5996                    if (
5997                        $formType == Configure::read('payment_prepaid_corporate_light_member') ||
5998                        $formType == Configure::read('payment_company_credit_corporate_light')
5999                    ) {
6000                        $saveUserArr['corporate_last_charge_date'] = $datetime;
6001                    }
6002
6003                    // if bonus coin flg is set
6004                    if (isset($ptpp['bonusCoinFlg'])) {
6005                        $saveUserArr['bonus_coin_flg'] = $ptpp['bonusCoinFlg'];
6006                    }
6007
6008                    // if first time payment
6009                    if (isset($userData['first_charge_date']) && $userData['first_charge_date'] == "0000-00-00 00:00:00") {
6010                        $saveUserArr['first_charge_date'] = $datetime;
6011                    }
6012
6013                    // get user zero student discount term
6014                    $discountOptionTermData = $this->UserDiscountOptionsTerm->getTerm([
6015                        'user_id' =>  $userId,
6016                        'discount_option_id' => Configure::read('discount_option.zero_student.plan_id'),
6017                        'status' => 1
6018                    ]);
6019
6020                    // stop zero student discount
6021                    if ($discountOptionTermData) {
6022                        // open tunnel
6023                        myTools::initializeApiTunnel(['DiscountOptionController']);
6024
6025                        // initialize controller
6026                        $doc = new DiscountOptionController(); 
6027
6028                        $zeroStudentDiscountCount = $this->DiscountOptionsSettlementHistory->countSuccessfulDiscount($discountOptionTermData['discount_option_term_id']);
6029                        $doshStatus = $zeroStudentDiscountCount ? Configure::read('discount_option.dosh_status.midterm_cancellation') : Configure::read('discount_option.dosh_status.maturity_cancellation');
6030
6031                        $docParams = [
6032                            'discountOptionId' => $discountOptionTermData['discount_option_id'],
6033                            'discountOptionPriceId' => $discountOptionTermData['discount_option_price_id'],
6034                            'termId' => $discountOptionTermData['discount_option_term_id'],
6035                            'cancellationFee' => 0,
6036                            'cancellationType' => Configure::read('discount_option.dosh_type.plan_change'),
6037                            'userData' => $userData,
6038                            'fromController' => $this->request->params['controller'],
6039                            'fromAction' => $this->request->params['action'],
6040                            'doshStatus' => $doshStatus
6041                        ];
6042
6043                        // set data
6044                        $doc->params = $docParams;
6045
6046                        if (!$doc->stopDiscountOption()) {
6047                            $this->log(__METHOD__ . ' Failed to stop discount option. ' . json_encode($docParams) . ' -- ' . json_encode($data), $logFileName);
6048                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to stop discount option. ', $docParams);
6049                            return ;
6050                        }
6051                    }
6052
6053                    if ($formType != Configure::read('payment_credit_change')) {
6054
6055                        //NJ-38376 : set the corporate light params on next charge date 
6056                        $nxtChargeLightParams = array(
6057                            'user_corporate_type' => $corpType,
6058                            'corporate_id' => $userData['corporate_id']
6059                        );
6060
6061
6062                        // get next charge date
6063                        if ($corpType == $corpTypeLight) {
6064                            $nextChargeDate = $this->User->corpLightNextChargeDate(false,$nxtChargeLightParams);
6065                        } else {
6066                            $nextChargeDate = $this->User->getCorporateNextChargeDate(false,$nxtChargeLightParams);
6067                        }
6068
6069                        $saveUserArr['next_charge_date'] = $nextChargeDate;
6070
6071                        // if corporate premium and card registration or force settlement
6072                        if (
6073                            $corpType == $corpTypePremium &&
6074                            ($logFileName == 'card_charge' || $logFileName == 'card_registration')
6075                        ) {
6076                            $saveUserArr['corporate_campaign_flg'] = 1;
6077                        }
6078                    }
6079
6080                    // NC-7779 : check if user has chivox monthly test taken for the current month, and monthly_speaking_attended_flg ON,
6081                    // turn Off the flag if users has not yet taken the exam for the current month.
6082                    if (
6083                        isset($userData['monthly_speaking_attended_flg']) && isset($userData['monthly_speaking_business_attended_flg'])
6084                        && ($userData['monthly_speaking_attended_flg'] == 1 || $userData['monthly_speaking_business_attended_flg'] == 1)
6085                    ) {
6086                        // check chivox monthly
6087                        $paymentPlanIdsForChivoxMonthly = Configure::read('chivox.monthly.user_payment_plan_cantake_exam');
6088                        if (in_array($paymentPlanId, $paymentPlanIdsForChivoxMonthly)) {
6089
6090                            // load model
6091                            $this->loadModel("UsersChivoxMonthlyTest");
6092                            $userTestMonthFlagParams['user_id'] = $userId;
6093                            $userTestMonthFlag = $this->UsersChivoxMonthlyTest->checkUserCurrentMonthExam($userTestMonthFlagParams);
6094
6095                            $monthly_speaking_attended_flg = Configure::read('chivox.test_data_test_type.daily'); // test_type daily speaking 0
6096                            $monthly_speaking_business_attended_flg = Configure::read('chivox.test_data_test_type.business'); // test_type business 1
6097
6098                            // if user hat not yet taken the exam for current month
6099                            if (!in_array($monthly_speaking_attended_flg, $userTestMonthFlag)) {
6100                                $saveUserArr['monthly_speaking_attended_flg'] = 0;
6101                            }
6102                            if (!in_array($monthly_speaking_business_attended_flg, $userTestMonthFlag)) {
6103                                $saveUserArr['monthly_speaking_business_attended_flg'] = 0;
6104                            }
6105                        }
6106                    }
6107
6108                    $this->User->clear();
6109                    if (!$this->User->read(array_keys($saveUserArr), $userId)) {
6110                        $this->log(__METHOD__ . ' User does not exist. --> ' . json_encode($saveUserArr) . ' -- ' . json_encode($data), $logFileName);
6111                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'User does not exist.', $data);
6112                        return ;
6113                    }
6114
6115                    $this->User->set($saveUserArr);
6116                    $this->User->validate = array();
6117
6118                    // rollback if updating user data failed.
6119                    if (!$saveUser = $this->User->save()) {
6120                        $this->log(__METHOD__ . ' Failed to update user data. --> ' . json_encode($saveUserArr) . ' -- ' . json_encode($data), $logFileName);
6121                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update user data.', $data);
6122                        return ;
6123                    }
6124
6125                    if ($formType != Configure::read('payment_credit_change')) {
6126                        /* --- get remaining points --- */
6127                        // note: only for premium, corporate standardard plan and light plan
6128
6129
6130                        $monthlyPoints = 0;
6131                        if (in_array($paymentPlanId, array(Configure::read('payment_plans.corporate_standard_card_plan'), Configure::read('payment_plans.corporate_premium_individual_plan'), Configure::read('payment_plans.corporate_premium_card_plan')))) {
6132                            $dateDiff = date('t');
6133                            $coins = $dateDiff * 100;
6134                            $coinType = 3; // corporate coins
6135                            $monthlyPoints = $this->UsersPoint->getCorporatePoints($userId, $coinType);
6136                            $memoCoins = 'MC';
6137                        } elseif (in_array($paymentPlanId, array(Configure::read('payment_plans.corporate_light_individual_plan'), Configure::read('payment_plans.corporate_light_card_plan')))) {
6138                            $corporate = $this->Corporate->find('first', array(
6139                                'fields' => array('light_limit'),
6140                                'conditions' => array('id' => $userData['corporate_id']),
6141                                'recursive' => -1
6142                            ));
6143
6144                            $lightLimit = isset($corporate['Corporate']['light_limit']) ?  $corporate['Corporate']['light_limit'] : 1;
6145                            $coins = $lightLimit * $this->Corporate->corpLightMonthlyCoin;
6146                            //if corporate_light_individual_plan grant sc and mc else grant mc
6147                            $coinType = $paymentPlanId == Configure::read('payment_plans.corporate_light_individual_plan') ? 5 : 3; // sc and mc coins
6148                            $monthlyPoints = $this->UsersPoint->getCorporatePoints($userId, $coinType);
6149                            $memoCoins = 'SC and MC';
6150                        }
6151
6152                        /* -- consfiscate points --- */
6153                        // note: only for premium,corporate standardard plan and light plan
6154
6155                        $updateMemo = '';
6156                        if (
6157                            (in_array($paymentPlanId, array(Configure::read('payment_plans.corporate_premium_individual_plan'), Configure::read('payment_plans.corporate_light_individual_plan'))) &&
6158                            $settlementType != $settlementTypes['card_registration']  || in_array($paymentPlanId, array(Configure::read('payment_plans.corporate_standard_card_plan'), Configure::read('payment_plans.corporate_premium_card_plan'), Configure::read('payment_plans.corporate_light_card_plan')))) && $monthlyPoints
6159                        ) {
6160                            $confiscateParams = array(
6161                                'userId' => $userId,
6162                                'point' => $monthlyPoints,
6163                                'kbn' => 18, // Administrator Change/Minus
6164                                'coinType' => $coinType
6165                            );
6166
6167                            // rollback if confiscating points failed
6168                            if (!$confiscateCoinFlg = $this->UsersPoint->confiscateCorporateUserPoints($confiscateParams)) {
6169                                $this->log(__METHOD__ . ' Failed to confiscate points. --> ' . json_encode($confiscateParams) . ' -- ' . json_encode($data), $logFileName);
6170                                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to confiscate points.', $data);
6171                                return ;
6172                            }
6173
6174                            $updateMemo = "\n {$datetime} (Previous Coins ({$memoCoins})【Confiscated】 : {$monthlyPoints}. )";
6175                        }
6176
6177                        /* -- add points and update memo --- */
6178                        // note: only for premium and light plan
6179                        if (in_array($paymentPlanId, array(Configure::read('payment_plans.corporate_premium_individual_plan'), Configure::read('payment_plans.corporate_light_individual_plan'), Configure::read('payment_plans.corporate_premium_card_plan'), Configure::read('payment_plans.corporate_light_card_plan')))) {
6180                            $pointParams = array(
6181                                'userId' => $userId,
6182                                'point' => $coins,
6183                                'kbn' => 19, // Corporate Complimentary (MC)
6184                                'kbnType' => 1, // add coin
6185                                'coinType' => 3, // corporate coin
6186                                'coinFailMessage' => Configure::read('coin.failed.membership')
6187                            );
6188
6189                            // rollback if adding points failed
6190                            if (!$this->UsersPoint->performPointTransaction($pointParams)) {
6191                                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'adding points failed.', $data);
6192                                return ;
6193                            }
6194
6195                            $planName = $paymentPlanId == Configure::read('payment_plans.corporate_light_individual_plan') ? 'Light' : 'Premium';
6196                            $updateMemo = "\n {$datetime} | Corporate {$planName} Plan Monthly Bonus Coins (MC): {$coins} {$updateMemo}";
6197                        // create point data if standard corporate type
6198                        } elseif (
6199                            $paymentPlanId == Configure::read('payment_plans.corporate_standard_individual_plan') && 
6200                            $settlementType == $settlementTypes['card_registration']
6201                        ) {
6202                            if (!$this->UsersPoint->createUsersPoint($userId)) {
6203                                $this->log(__METHOD__ . ' Failed to create users point data. --> ' . json_encode($data), $logFileName);
6204                                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to create users point data.', $data);
6205                                return ;
6206                            }
6207                        }
6208
6209                        if (!empty($updateMemo)) {
6210                            $updateMemo = $updateMemo . "\n" . $userData['memo'];
6211                            $this->User->read(array('memo'), $userId);
6212                            $this->User->set(array('memo' => $updateMemo));
6213                            $this->User->validate = array();
6214
6215                            // rollback if updating memo failed
6216                            if (!$this->User->save()) {
6217                                $this->log(__METHOD__ . ' Failed update user memo. ' . json_encode($updateMemo) . ' -- ' . json_encode($data), $logFileName);
6218                                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed update user memo.', $data);
6219                                return ;
6220                            }
6221                        }
6222                    }
6223
6224                    // set deactivation time
6225                    if (isset($ptpp['corporate_deactivation_time'])) {
6226                        $this->CorporateScheduledDeactivation->clear();
6227                        $this->CorporateScheduledDeactivation->create();
6228
6229                        $cdtParams = array(
6230                            'user_id' => $userId,
6231                            'deactivation_date' => $ptpp['corporate_deactivation_time'],
6232                            'status' => 0
6233                        );
6234                        $this->CorporateScheduledDeactivation->set($cdtParams);
6235
6236                        if (!$this->CorporateScheduledDeactivation->save()) {
6237                            $this->log(__METHOD__ . ' Failed to set deactivation time. --> ' . json_encode($cdtParams) . ' -- ' . json_encode($data), $logFileName);
6238                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to set deactivation time.', $data);
6239                            return ;
6240                        }
6241                    }
6242                } elseif ($formType == Configure::read('payment_credit_coin_purchase')) {
6243                    $coinPurchasePoints = intVal($ptpp['coinPurchasePoints']);
6244                    $coinData = $this->UsersPoint->SET_charge_overseas_menue($coinPurchasePoints, $currencyCode);
6245
6246                    // NC-5007 add to the user's existing coin
6247                    $pcCorZeusPay = array(
6248                        'userId' => $userId,
6249                        'point' => $coinData['num_of_coin'] - $coinData['bonus_coin'],
6250                        'kbn' => 7,
6251                        'kbnType' => 1, // add coin
6252                        'coinType' => 1, // purchase coin
6253                        'coinFailMessage' => Configure::read('coin.failed.buy_coin'),
6254                        'device' => isset($ptpp['device']) ? $ptpp['device'] : null
6255                    );
6256    
6257                    $scCorZeusPay = array(
6258                        'userId' => $userId,
6259                        'point' => $coinData['bonus_coin'],
6260                        'kbn' => 7,
6261                        'kbnType' => 1, // add coin
6262                        'coinType' => 2, // service coin
6263                        'coinFailMessage' => Configure::read('coin.failed.buy_coin'),
6264                        'device' => isset($ptpp['device']) ? $ptpp['device'] : null
6265                    );
6266
6267                    $pointParams = [$pcCorZeusPay, $scCorZeusPay];
6268
6269                    // NC-5007 add to the user's existing coin
6270                    if ( $pointParams ) {
6271                        foreach($pointParams as $key => $val) {
6272                            if (!$this->UsersPoint->performPointTransaction($val)) {
6273                                $this->log(__METHOD__ . ' Failed to add user point. ' . json_encode($val) . ' -- ' . json_encode($data), $logFileName);
6274                                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to add user point', $data, $val);
6275                                return ;
6276                            }
6277                        }
6278                    }
6279
6280                    $cpilData = array(
6281                        'payment_id' => $this->Payment->id,
6282                        'form_type' => $formType,
6283                        'corporate_id' => $corporateId
6284                    );
6285
6286                    // rollback and return if failed to save payment id
6287                    if (!$this->CorporatePaymentIdLog->saveData($cpilData)) {
6288                        $this->log(__METHOD__ . ' Failed to save corporate payment id log data. ' . json_encode($cpilData) . ' -- ' . json_encode($data), $logFileName);
6289                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save corporate payment id log data.', $data);
6290                        return ;
6291                    }
6292                } elseif ($formType == Configure::read('payment_credit_textbook_purchase')) {
6293                    // set textbook sales info
6294                    $textbookSales = $this->TextbookSale->find('first', array(
6295                        'conditions' => array('TextbookSale.sales_code' => $ptPassword),
6296                        'recursive' => -1
6297                    ));
6298
6299                    // if has textbook sales, update payment_id
6300                    if ($textbookSales) {
6301                        $this->TextbookSale->clear();
6302                        if (!$this->TextbookSale->read(null, $textbookSales['TextbookSale']['id'])) {
6303                            $this->log(__METHOD__ . ' Textbook sales id does not exist. --> ' . json_encode($textbookSales), $logFileName);
6304                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Textbook sales id does not exist.', $data);
6305                            return ;
6306                        }
6307
6308                        $this->TextbookSale->set('payment_id', $this->Payment->id);
6309                        $this->TextbookSale->set('payment_status', 1);
6310                        if (!$this->TextbookSale->save()) {
6311                            $this->log(__METHOD__ . ' Failed update textbook sales payment status to 1. --> ' . json_encode($textbookSales), $logFileName);
6312                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed update textbook sales payment status to 1.', $data);
6313                            return ;
6314                        }
6315
6316                        $cpilData = array(
6317                            'payment_id' => $this->Payment->id,
6318                            'form_type' => $formType,
6319                            'corporate_id' => $corporateId
6320                        );
6321
6322                        // rollback and return if failed to save payment id
6323                        if (!$this->CorporatePaymentIdLog->saveData($cpilData)) {
6324                            $this->log(__METHOD__ . ' Failed to save corporate payment id log data. ' . json_encode($cpilData) . ' -- ' . json_encode($data), $logFileName);
6325                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save corporate payment id log data.', $data);
6326                            return ;
6327                        }
6328                    }
6329                } elseif ($formType == Configure::read('corporate_credit_card_registration')) {
6330                    $saveUserArr = array(
6331                        'card_number' => $data['cardnumber'],
6332                        'card_brand' => $data['cardbrand'],
6333                        'card_company' => $cardCompany
6334                    );
6335
6336                    // update user info
6337                    $this->User->clear();
6338                    if (!$this->User->read(array_keys($saveUserArr), $userId)) {
6339                        $this->log(__METHOD__ . ' User does not exist. --> ' . json_encode($saveUserArr) . ' -- ' . json_encode($data), $logFileName);
6340                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'User does not exist.', $data);
6341                        return ;
6342                    }
6343
6344                    $this->User->set($saveUserArr);
6345                    $this->User->validate = array();
6346
6347                    // rollback if updating user data failed.
6348                    if (!$saveUser = $this->User->save()) {
6349                        $this->log(__METHOD__ . ' Failed to update user data. --> ' . json_encode($saveUserArr) . ' -- ' . json_encode($data), $logFileName);
6350                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update user data.', $data);
6351                        return ;
6352                    }
6353                } elseif (in_array($formType, array($formTypeIndiLightLesson, $formTypeComCardLightlLesson)) && $settlementType == $settlementTypes['lesson_fee_payment']) {
6354                    // update corporate last charge date
6355                    $this->User->clear();
6356
6357                    if (!$this->User->read(array('corporate_last_charge_date'), $userId)) {
6358                        $this->log(__METHOD__ . ' User does not exist. --> ' . json_encode($userId) . ' -- ' . json_encode($data), $logFileName);
6359                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, ' User does not exist.', $data);
6360                        return ;
6361                    }
6362
6363                    $this->User->set(array('corporate_last_charge_date' => date('Y-m-d H:i:s')));
6364                    if (!$this->User->save()) {
6365                        $this->log(__METHOD__ . ' Failed to update user corporate_last_charge_date. --> ' . json_encode($userId) . ' -- ' . json_encode($data), $logFileName);
6366                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, ' Failed to update user corporate_last_charge_date.', $data);
6367                        return ;
6368                    }
6369                }
6370
6371                // if card expiration date is not empty
6372                if (
6373                    isset($cardExpirationDate) &&
6374                    !in_array($paymentPlanId, array(Configure::read('payment_plans.corporate_standard_card_plan'), Configure::read('payment_plans.corporate_premium_card_plan')))
6375                ) {
6376                    $this->User->clear();
6377                    $cedData = array('card_expiration_date' => $cardExpirationDate);
6378                    if (!$this->User->read(array_keys($cedData), $userId)) {
6379                        $this->log(__METHOD__ . ' User not found. --> ' . json_encode($userId), $logFileName);
6380                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'User not found.', $data);
6381                        return ;
6382                    }
6383
6384                    $this->User->set($cedData);
6385                    if (!$this->User->save()) {
6386                        $this->log(__METHOD__ . ' Failed to update card expiration date. --> ' . json_encode($cedData) . ' -- ' . json_encode($data), $logFileName);
6387                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to set deactivation time.', $data);
6388                        return ;
6389                    }
6390                }
6391
6392                // [ZEUS] Corporate
6393                if (
6394                    in_array($formType, array(
6395                        Configure::read('payment_credit_receivable'),
6396                        Configure::read('payment_individual_corporate_standard'),
6397                        Configure::read('payment_individual_corporate_premium'),
6398                        Configure::read('payment_prepaid_corporate_light_member'),
6399                        Configure::read('payment_credit_change'),
6400                        Configure::read('corporate_credit_card_registration')
6401                    ))
6402                ) {
6403                    // get current payment_id
6404                    $originalPaymentId = isset($this->Payment->id) ? $this->Payment->id : null;
6405                    
6406                    // create new payment receivable
6407                    if ($receivablePayment) {
6408                        // set payment id
6409                        $data["payment_id"] = $originalPaymentId;
6410                        $paymentData = array(
6411                            'user_id' => $userId,
6412                            'amount' => $receivablePayment,
6413                            'status' => 1,
6414                            'type_id' => 1,
6415                            'reference_id' => $data['sendid'],
6416                            'card_company' => $cardCompany,
6417                            'param1' => json_encode($data),
6418                            'form_type' => Configure::read('payment_credit_receivable'),
6419                            'ordd' => $ordd,
6420                            'currency_code' => $currencyCode,
6421                            'transaction_code' => $paymentHash,
6422                            'price_id' => $priceId,
6423                            'payment_id' => $paymentPlanId,
6424                            'payment_type' => $paymentType,
6425                            'discounted_amount' => $discounted_amount
6426                        );
6427
6428                        // create new payment
6429                        $this->Payment->clear();
6430                        $this->Payment->create();
6431                        $this->Payment->set($paymentData);
6432
6433                        if (!$this->Payment->save()) {
6434                            $this->log(__METHOD__ . ' Failed to save payment data. --> ' . json_encode($paymentData), $logFileName);
6435                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data.', $data);
6436                            return ;
6437                        }
6438
6439                        //update/add user`s settlement amount
6440                        $this->User->updateUserPayments($paymentData);
6441
6442                        // set payment_id
6443                        $paymentID = $this->Payment->id;
6444
6445                        // set payment receivable statuses to 2 - received
6446                        $this->PaymentReceivable->updateReceivableReservationPayment(
6447                            $userId,
6448                            array(
6449                                'status' => 2,
6450                                'payment_id' => $paymentID,
6451                                'payment_collection_date' => date("Y-m-d H:i:s"),
6452                                'card_company' => $cardCompany,
6453                                'payment_plan_id' => $paymentPlanId,
6454                                'membership_type_index' => $membershipStatusIndex
6455                            ),
6456                            array(
6457                                'PaymentReceivable.user_id' => $userId,
6458                                'PaymentReceivable.status' => 0,
6459                                'PaymentReceivable.payment_element_type' => 1,
6460                                'PaymentReceivable.created <=' => $cronDateRun
6461                            )
6462                        );
6463                    }
6464                    
6465                    // [ZEUS] Corporate Appreciation
6466                    if ($appreciationReceivable) {
6467                        $data["payment_id"] = $originalPaymentId;
6468                        $paymentData = array(
6469                            'user_id' => $userId,
6470                            'amount' => $appreciationReceivable,
6471                            'status' => 1,
6472                            'type_id' => 1,
6473                            'reference_id' => $data['sendid'],
6474                            'card_company' => $cardCompany,
6475                            'param1' => json_encode($data),
6476                            'form_type' => Configure::read('appreciation_data.payment_form_type'),
6477                            'ordd' => $ordd,
6478                            'currency_code' => $currencyCode,
6479                            'transaction_code' => $paymentHash,
6480                            'price_id' => $priceId,
6481                            'payment_id' => $paymentPlanId,
6482                            'payment_type' => $paymentType,
6483                            'discounted_amount' => $discounted_amount
6484                        );
6485
6486                        // create new payment
6487                        $this->Payment->clear();
6488                        $this->Payment->create();
6489                        $this->Payment->set($paymentData);
6490
6491                        if (!$this->Payment->save()) {
6492                            $this->log(__METHOD__ . ' Failed to save appreciationReceivable payment data. --> ' . json_encode($paymentData), $logFileName);
6493                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data.', $data);
6494                            return ;
6495                        }
6496
6497                        //update/add user`s settlement amount
6498                        $this->User->updateUserPayments($paymentData);
6499
6500                        // set payment_id
6501                        $paymentID = $this->Payment->id;
6502
6503                        // set payment receivable for appreciation statuses to 2 - received
6504                        $this->PaymentReceivable->updateReceivableReservationPayment(
6505                            $userId,
6506                            array(
6507                                'status' => 2,
6508                                'payment_id' => $paymentID,
6509                                'payment_collection_date' => date("Y-m-d H:i:s"),
6510                                'card_company' => $cardCompany,
6511                                'payment_plan_id' => $paymentPlanId,
6512                                'membership_type_index' => $membershipStatusIndex
6513                            ),
6514                            array(
6515                                'PaymentReceivable.user_id' => $userId,
6516                                'PaymentReceivable.status' => 0,
6517                                'PaymentReceivable.payment_element_type' => Configure::read('appreciation_data.payment_element_type'), // Appreciation
6518                                'PaymentReceivable.created <=' => $cronDateRun
6519                            )
6520                        );
6521                    }
6522
6523                    // debug log
6524                    $this->log("[ZEUSPAY_CORPORATE_APPRECIATION_RECEIVABLE] kickback was recieved -> " . json_encode($data), $logFileName);
6525
6526                    // [ZEUS] Corporate Live
6527                    if ($liveLessonReceivable) {
6528                        $data["payment_id"] = $originalPaymentId;
6529                        $paymentData = array(
6530                            'user_id' => $userId,
6531                            'amount' => $liveLessonReceivable,
6532                            'status' => 1,
6533                            'type_id' => 1,
6534                            'reference_id' => $data['sendid'],
6535                            'card_company' => $cardCompany,
6536                            'param1' => json_encode($data),
6537                            'form_type' => Configure::read('payment_live_lesson_receivable'),
6538                            'ordd' => $ordd,
6539                            'currency_code' => $currencyCode,
6540                            'transaction_code' => $paymentHash,
6541                            'price_id' => $priceId,
6542                            'payment_id' => $paymentPlanId,
6543                            'payment_type' => $paymentType,
6544                            'discounted_amount' => $discounted_amount
6545                        );
6546
6547                        // create new payment
6548                        $this->Payment->clear();
6549                        $this->Payment->create();
6550                        $this->Payment->set($paymentData);
6551
6552                        if (!$this->Payment->save()) {
6553                            $this->log(__METHOD__ . ' Failed to save liveLessonReceivable payment data. --> ' . json_encode($paymentData), $logFileName);
6554                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data.', $data);
6555                            return ;
6556                        }
6557
6558                        //update/add user`s settlement amount
6559                        $this->User->updateUserPayments($paymentData);
6560
6561                        // set payment_id
6562                        $paymentID = $this->Payment->id;
6563
6564                        // set payment receivable for live statuses to 2 - received
6565                        $this->PaymentReceivable->updateReceivableReservationPayment(
6566                            $userId,
6567                            array(
6568                                'status' => 2,
6569                                'payment_id' => $paymentID,
6570                                'payment_collection_date' => date("Y-m-d H:i:s"),
6571                                'card_company' => $cardCompany,
6572                                'payment_plan_id' => $paymentPlanId,
6573                                'membership_type_index' => $membershipStatusIndex
6574                            ),
6575                            array(
6576                                'PaymentReceivable.user_id' => $userId,
6577                                'PaymentReceivable.status' => 0,
6578                                'PaymentReceivable.payment_element_type' => Configure::read('payment_element_type.live'),
6579                                'PaymentReceivable.created <=' => $cronDateRun
6580                            )
6581                        );
6582                    }
6583                    
6584                    // debug log
6585                    $this->log("[ZEUSPAY_CORPORATE_LIVE_RECEIVABLE] kickback was recieved -> " . json_encode($data), $logFileName);
6586
6587                }
6588
6589                // if has native speaker payment
6590                if ($nativeOptionPayment > 0 && $formType != Configure::read('payment_native_option_join')) {
6591                    $paymentData['amount'] = $ptpp['nativeOptionPayment'];
6592                    $paymentData['form_type'] = Configure::read('payment_native_option_monthly_payment');
6593
6594                    // create new payment
6595                    $this->Payment->clear();
6596                    $this->Payment->create();
6597                    $this->Payment->set($paymentData);
6598                    $this->Payment->validate = array();
6599                    $this->Payment->set($paymentData);
6600
6601                    if (!$this->Payment->save()) {
6602                        $this->log(__METHOD__ . ' Failed to save native option payment data. --> ' . json_encode($paymentData) . ' -- ' . json_encode($data), $logFileName);
6603                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save native option payment data.', $data);
6604                        return ;
6605                    }
6606
6607                    //update/add user`s settlement amount
6608                    $this->User->updateUserPayments($paymentData);
6609                }
6610
6611                // if has callan unli option payment
6612                if ($callanOptionPayment > 0 && $formType != Configure::read('payment_callan_option_join')) {
6613                    $paymentData['amount'] = $ptpp['callanOptionPayment'];
6614                    $paymentData['form_type'] = Configure::read('payment_callan_option_monthly_payment');
6615
6616                    // create new payment
6617                    $this->Payment->clear();
6618                    $this->Payment->create();
6619                    $this->Payment->set($paymentData);
6620                    $this->Payment->validate = array();
6621                    $this->Payment->set($paymentData);
6622
6623                    if (!$this->Payment->save()) {
6624                        $this->log(__METHOD__ . ' Failed to save native option payment data. --> ' . json_encode($paymentData) . ' -- ' . json_encode($data), $logFileName);
6625                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save native option payment data.', $data);
6626                        return ;
6627                    }
6628
6629                    //update/add user`s settlement amount
6630                    $this->User->updateUserPayments($paymentData);
6631                }
6632
6633                // activate user native option
6634                if (isset($ptpp['nativeOptionJoin']) && $ptpp['nativeOptionJoin']) {
6635                    $this->User->clear();
6636                    $unliNativePersonalCardFlg = $this->User->field('unli_native_personal_card_flg', array('User.id' => $userId));
6637                    if (isset($unliNativePersonalCardFlg) && $unliNativePersonalCardFlg != 1) { // prevent duplicate running userNativeOptionProcess function
6638                        if (!$this->User->userNativeOptionProcess(array('user_id' => $userId, 'type' => 'on'))) {
6639                            $this->log(__METHOD__ . 'Failed to update native option. --> ' . json_encode($paymentData) . ' -- ' . json_encode($data), $logFileName);
6640                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update native option.', $data);
6641                            return ;
6642                        }
6643                    }
6644
6645                    //NJ-2814 add logs
6646                    if (isset($ptpp['nativeOptionJoin']) && $ptpp['nativeOptionJoin']) {
6647                        $nativeStatus = 1; // subscribed
6648                        $statusBefore = '';
6649                    } else {
6650                        $nativeStatus = 2; // Monthly Continue
6651                        $statusBefore = 1;
6652                    }
6653
6654                    $optionLogParams = array(
6655                        'user_id' => $userId,
6656                        'platform' => $ptpp['platform'],
6657                        'status' => $nativeStatus,
6658                        'controller_name' => $this->request->params['controller'],
6659                        'action_name' => $this->request->params['action'],
6660                        'user_type' => 0, // user
6661                        'option_before' => $statusBefore,
6662                        'option_after' => 1,
6663                        'option_before_name' => '',
6664                        'option_after_name' => 'Native Unlimited Option',
6665                        'payment_plan_id' => $paymentPlanId
6666                    );
6667
6668                    ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
6669
6670                    $charge_flg = 0;                    
6671                    if (isset($ptpp['corporatePersonalCardFlg']) && $ptpp['corporatePersonalCardFlg']) { 
6672                        $charge_flg = $ptpp['corporatePersonalCardFlg'];
6673                    }
6674
6675                    $insertCPRData = array(
6676                        'corporate_id' => $corporateId,
6677                        'user_id' => $userId,
6678                        'type' => $this->CorporatesPaymentReceivable->typeCorporateNativeOptionJoin,
6679                        'status' => 1, // paid
6680                        'charge_flg' => $charge_flg,
6681                        'quantity' => 1,
6682                        'amount' => $ptpp['nativeOptionPayment'],
6683                        'discount' => 0,
6684                        'next_settlement' => date('Y-m-d 00:00:00')
6685                    );
6686
6687                    // create corporate payment receivable
6688                    if (!$this->CorporatesPaymentReceivable->addReceivablePayment($insertCPRData)) {
6689                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to create payment receivable.', $data);
6690                        return ;
6691                    }
6692                }
6693
6694                // -  activate user callan option
6695                if (isset($ptpp['callanOptionJoin']) && $ptpp['callanOptionJoin']) {
6696
6697                    $charge_flg = 0;
6698                    if (isset($ptpp['corporatePersonalCardFlg']) && $ptpp['corporatePersonalCardFlg']) {
6699                        $charge_flg = $ptpp['corporatePersonalCardFlg'];
6700                    }
6701
6702                    // - option process data
6703                    $optionProcessData = array(
6704                            'user_id' => $userId,
6705                            'type' => 'on',
6706                            'option_type' => Configure::read('callan_unlimited.options.callan_unlimited_option'),
6707                            'corp_student_personal_card' => $charge_flg
6708                    );
6709                    if (!$this->User->userNativeOptionProcess($optionProcessData)) {
6710                        $this->log(__METHOD__ . 'Failed to update native option. --> ' . json_encode($paymentData) . ' -- ' . json_encode($data), $logFileName);
6711                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update callan option.', $data);
6712                        return;
6713                    }
6714
6715
6716                    $insertCPRData = array(
6717                            'corporate_id' => $corporateId,
6718                            'user_id' => $userId,
6719                            'type' => $this->CorporatesPaymentReceivable->typeCorporateCallanOptionJoin,
6720                            'status' => 1, // paid
6721                            'charge_flg' => $charge_flg,
6722                            'quantity' => 1,
6723                            'amount' => $ptpp['callanOptionPayment'],
6724                            'discount' => 0,
6725                            'next_settlement' => date('Y-m-d 00:00:00')
6726                    );
6727
6728                    // create corporate payment receivable
6729                    if (!$this->CorporatesPaymentReceivable->addReceivablePayment($insertCPRData)) {
6730                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to create payment receivable.', $data);
6731                        return ;
6732                    }
6733                }
6734
6735                // [ZEUS] Corporate individual allow appreciation
6736                if (
6737                    in_array($formType, array(
6738                        Configure::read('corporate_credit_card_registration'),
6739                        Configure::read('payment_individual_corporate_standard'),
6740                        Configure::read('payment_individual_corporate_premium'),
6741                        Configure::read('payment_prepaid_corporate_light_member')
6742                    ))
6743                ) {
6744                    // NJ-1562 - appreciation on
6745                    if( $paymentPlanId && in_array( $paymentPlanId, Configure::read('appreciation.payment_plan_id') ) ) {
6746                        $saveUserArr['allow_appreciation_flg'] = 1; // on NJ-7548 corporate individual allow appreciation
6747
6748                        //check if not on family plan
6749                        if (
6750                            !in_array($paymentPlanId, Configure::read('appreciation.can_coin_purchase_check')) 
6751                        ) {
6752                            //NJ-7548 fetch the user birthday and age 
6753                            $userAge = UserTable::getStudentAge($userData['birthday']);
6754                            $userAge = $userAge ? (int) $userAge : null;
6755                            $showAppreciationFlg = 0;
6756
6757                            //change the show appreciation flg if no birthday set or 18 and above            
6758                            if (!$userAge || $userAge >= 18) {
6759                                $showAppreciationFlg = 1;
6760                            }
6761
6762                            //set to save show appreciation flg 
6763                            $saveUserArr['show_appreciation_flg'] = $showAppreciationFlg;
6764                        }
6765
6766                        // update user info
6767                        $this->User->clear();
6768                        if (!$this->User->read(array_keys($saveUserArr), $userId)) {
6769                            $this->log(__METHOD__ . ' User does not exist. --> ' . json_encode($saveUserArr) . ' -- ' . json_encode($data), $logFileName);
6770                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'User does not exist.', $data);
6771                            return ;
6772                        }
6773
6774                        $this->User->set($saveUserArr);
6775                        $this->User->validate = array();
6776
6777                        // rollback if updating user data failed.
6778                        if (!$saveUser = $this->User->save()) {
6779                            $this->log(__METHOD__ . ' Failed to update user data. --> ' . json_encode($saveUserArr) . ' -- ' . json_encode($data), $logFileName);
6780                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update user data.', $data);
6781                            return ;
6782                        }
6783                    }
6784                }
6785
6786                // update corporate activation management data
6787                // add corporate activation management log
6788                if (isset($ptpp['camData']) ) {
6789                    $camData = $ptpp['camData'];
6790                    $camUpdateData = [];
6791
6792                    // if start/resume plan
6793                    if (isset($camData['startCorporatePlan']) && $camData['startCorporatePlan']) {
6794                        $camUpdateData['reserve_plan_status'] = 2; // started
6795                    }
6796
6797                    // if start/resume native option plan
6798                    if (
6799                        (isset($ptpp['nativeOptionPayment']) && $ptpp['nativeOptionPayment'] > 0) ||
6800                        isset($ptpp['callanOptionPayment']) && $ptpp['callanOptionPayment'] > 0
6801                    ) {
6802                        $camUpdateData = ['native_option_plan_status' => 2]; // started
6803                    }
6804
6805                    if (isset($camData['camId'])) {
6806                        $camUpdateData += [
6807                            'reserve_plan_id' => $corpType,
6808                            'reserve_plan_start_date' => date("Y-m-d H:i:s"),
6809                            'reserve_plan_status' => 2,
6810                            'temporary_next_charge_date' => $nextChargeDate
6811                        ];
6812
6813                        if (!$camRes = $this->CorporateActivationManagement->updateCAMData($camUpdateData, $camData['camId'])) {
6814                            $this->log(__METHOD__ . ' Failed to update corporate activation management data. --> ' . json_encode($camUpdateData) . ' -- ' . json_encode($data), $logFileName);
6815                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update corporate activation management data.', $data);
6816                            return ;
6817                        }
6818                    } else {
6819                        $camlInsertData = [
6820                            'user_id' => $userId,
6821                            'corporate_id' => $corporateId,
6822                            'reserve_plan_id' => $corpType,
6823                            'reserve_plan_start_date' => date("Y-m-d H:i:s"),
6824                            'reserve_plan_status' => 2,
6825                            'temporary_next_charge_date' => $nextChargeDate,
6826                            'temporary_pw_flg' => 0,
6827                            'new_user_flg' => 0
6828                        ];
6829
6830                        $camInsertData = [
6831                            'user_id' => $userId,
6832                            'corporate_id' => $corporateId,
6833                            'reserve_plan_id' => $corpType,
6834                            'reserve_plan_start_date' => date("Y-m-d H:i:s"),
6835                            'reserve_plan_status' => 2,
6836                            'temporary_next_charge_date' => $nextChargeDate,
6837                            'temporary_pw_flg' => 0,
6838                            'new_user_flg' => 0
6839                        ];
6840    
6841                        if (!$camRes = $this->CorporateActivationManagement->addCAMData($camInsertData)) {
6842                            $this->log(__METHOD__ . ' Failed to save corporate activation management data. --> ' . json_encode($camInsertData) . ' -- ' . json_encode($data), $logFileName);
6843                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save corporate activation management data.', $data);
6844                            return ;
6845                        }
6846                        $camlInsertData['cam_id'] = $camRes['id'];
6847                        $camlInsertData['transaction_type'] = 1; // add
6848                    }
6849
6850                    $camlInsertData = $camRes['CorporateActivationManagement'];
6851                    $camlInsertData['cam_id'] = $camlInsertData['id'];
6852                    $camlInsertData['transaction_type'] = 2; // update
6853                    unset($camlInsertData['id']);
6854                    unset($camlInsertData['created']);
6855                    unset($camlInsertData['modified']);
6856                    unset($camlInsertData['created_ip']);
6857                    unset($camlInsertData['modified_ip']);
6858
6859                    if (!$this->CorporateActivationManagementLog->addLog($camlInsertData)) {
6860                        $this->log(__METHOD__ . ' Failed to add corporate activation management log. --> ' . json_encode($camUpdateData) . ' -- ' . json_encode($data), $logFileName);
6861                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to add corporate activation management log.', $data);
6862                        return ;
6863                    }
6864
6865                    $isResume = $this->CorporateActivationManagementLog->isResume($userId);
6866                    $corpCat = $this->CorporateCategory->getDataById($corporateId);
6867                    $corpCat = isset($corpCat['CorporateCategory']) ? $corpCat['CorporateCategory'] : [];
6868                    $mtPassword = null; // mail template password
6869                    if (isset($ptpp['fromCron'])) {
6870                        if ($isResume) {
6871                            $templateId = isset($corpCat['resumption_template_id']) ? $corpCat['resumption_template_id'] : Configure::read('site_in_mail.resume_corporate_mail');
6872                        } else {
6873                            $templateId = isset($corpCat['usage_start_template_id']) ? $corpCat['usage_start_template_id'] : Configure::read('site_in_mail.usage_start_corporate_mail');
6874                        }
6875                    } else {
6876                        if ($isResume) {
6877                            $templateId = isset($corpCat['resume_now_template_id']) ? $corpCat['resume_now_template_id'] : Configure::read('site_in_mail.resume_corporate_mail');
6878                        } else {
6879                            $templateId = isset($corpCat['registration_template_id']) ? $corpCat['registration_template_id'] : Configure::read('site_in_mail.new_corporate_mail');
6880                            if ($camlInsertData['temporary_pw_flg']) {
6881                                $mtPassword = myTools::randStringWithSpecialChar(16);
6882    
6883                                // update user's password
6884                                if (!$this->User->updateUserById(['userData' => ['password' => Security::hash($mtPassword, null, true)], 'id' => $userId])) {
6885                                    $this->log(__METHOD__ . ' Failed to update user password. --> ' . json_encode($mtPassword) . ' -- ' . json_encode($data), $logFileName);
6886                                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update user password.', $data);
6887                                    return ;
6888                                }
6889                            }
6890                        }
6891                    }
6892
6893                    $corporateTypes = Configure::read('corporate_type_arr');
6894                    $mailData = [
6895                        'corporate_plan_type' => $corporateTypes[$corporateId],
6896                        'nickname' => $userData['nickname'],
6897                        'email' => $userData['email'],
6898                        'password' => $mtPassword
6899                    ];
6900
6901                    // send mail
6902                    myMailer::sendTemplateMail($templateId, $mailData['email'], $mailData, [], 'User');
6903                    
6904                }
6905
6906                // NJ-23781- update individual_card_fail_flg : success
6907                $updateIndividualCardFlgParams['individual_card_fail_flg'] = 0;
6908                $res_update_card_fail_flg = $this->update_card_fail_flg($updateIndividualCardFlgParams);
6909
6910                $ptStatus = 1;
6911
6912            // kickback result is NG
6913            } else {
6914                $nativeOptionChanged = $callanOptionChanged = 0;
6915
6916                if (
6917                    $formType != Configure::read('payment_credit_receivable') &&
6918                    $formType != Configure::read('payment_credit_appreciation_receivable') &&
6919                    $formType != Configure::read('corporate_credit_card_registration') &&
6920                    $formType != Configure::read('payment_credit_textbook_purchase') &&
6921                    $formType != Configure::read('payment_credit_coin_purchase') &&
6922                    $formType != Configure::read('payment_prepaid_corporate_light_member_lesson') &&
6923                    $formType != Configure::read('payment_company_credit_corporate_light_lesson') &&
6924                    $formType != Configure::read('payment_credit_change') &&
6925                    $formType != Configure::read('payment_native_option_join') &&
6926                    $formType != Configure::read('payment_callan_option_join') &&
6927                    $formType != Configure::read('payment_native_option_monthly_payment') &&
6928                    $formType != Configure::read('payment_callan_option_monthly_payment') &&
6929                    $settlementType != $settlementTypes['force_charge_payment'] &&
6930                    $settlementType != $settlementTypes['lesson_fee_payment'] &&
6931                    isset($userData['corporate_id']) && isset($userData['payment_plan_id'])
6932                ) {
6933                    $userUpdate = array(
6934                        'fail_flg' => 1,
6935                        'counseling_attended_flg' => 1,
6936                        'charge_flg' => 0,
6937                        'allow_appreciation_flg' => 0,
6938                        'show_appreciation_flg' => 0,
6939                        'next_charge_date' => NULL
6940                    );
6941
6942                    // if card_registration
6943                    if ($logFileName == 'card_registration') {
6944                        $userUpdate['status'] = 1;
6945                    }
6946
6947                    $this->User->validate = array();
6948                    if (!$this->User->read(array_keys($userUpdate), $userId)) {
6949                        $this->log(__METHOD__ . ' User does not exist. --> ' . json_encode($userData), $logFileName);
6950                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'User does not exist.', $data);
6951                        return ;
6952                    }
6953
6954                    // set native option to 0 if individual premium or standard user
6955                    $userUpdate['native_option'] = 0;
6956                    $userUpdate['unli_native_personal_card_flg'] = 0;
6957                    if (isset($userData['native_option']) && $userData['native_option']) {
6958                        $userUpdate['native_option_cancellation_time'] = date("Y-m-d H:i:s");
6959                        $nativeOptionChanged = 1;
6960                    }
6961
6962                    // cancel native option payment
6963                    $this->CorporatesPaymentReceivable->updateAll(
6964                        array(
6965                            'status' => 2,
6966                            'modified' => "'" . date("Y-m-d H:i:s") . "'"
6967                        ),
6968                        array(
6969                            'user_id' => $userId,
6970                            'type' => $this->CorporatesPaymentReceivable->typeCorporateNativeOptionMonthly,
6971                            'status' => 0
6972                        )
6973                    );
6974
6975                    // set callan option to 0 if individual premium or standard user
6976                    $userUpdate['callan_option'] = 0;
6977                    $userUpdate['unli_callan_personal_card_flg'] = 0;
6978                    if (isset($userData['callan_option']) && $userData['callan_option']) {
6979                        $userUpdate['callan_option_cancellation_time'] = date("Y-m-d H:i:s");
6980                        $callanOptionChanged = 1;
6981                    }
6982                    // cancel callan option payment
6983                    $this->CorporatesPaymentReceivable->updateAll(
6984                        array(
6985                            'status' => 2,
6986                            'modified' => "'" . date("Y-m-d H:i:s") . "'"
6987                        ),
6988                        array(
6989                            'user_id' => $userId,
6990                            'type' => $this->CorporatesPaymentReceivable->typeCorporateCallanOptionMonthly,
6991                            'status' => 0
6992                        )
6993                    );
6994
6995                    $this->User->validate = array();
6996                    if (!$this->User->read(array_keys($userUpdate), $userId)) {
6997                        $this->log(__METHOD__ . ' User does not exist. --> ' . json_encode($userData), $logFileName);
6998                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'User does not exist.', $data);
6999                        return ;
7000                    }
7001
7002                    $this->User->set($userUpdate);
7003                    if (!$this->User->save()) {
7004                        $this->log(__METHOD__ . ' Failed to update user data. ' . json_encode($userUpdate), $logFileName);
7005                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update user data.', $data);
7006                        return ;
7007                    }
7008
7009                    // update user who join in ContinuationCampaign to fail status - 3
7010                    $this->ContinuationCampaign->setFailedUser(array(
7011                        'user_id' => $userId
7012                    ));
7013
7014                }
7015
7016                $individualUserUpdate = [];
7017                // set error code
7018                $data['error_code'] = Configure::read('zeus.error.ng_return');
7019                $data['formType'] = $formType;
7020
7021                if ($usingCompanyCard) {
7022                    $data['user_id'] = $userId;
7023                    $data['sendid'] = $corporateId;
7024                }
7025
7026                if (!$this->_error_log_set($data, $ptpp)) {
7027                    $this->log(__METHOD__ . ' Failed to save payment data. ' . json_encode($userUpdate), $logFileName);
7028                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data.', $data);
7029                    return ;
7030                }
7031
7032                if ($nativeOptionPayment > 0 && $formType != Configure::read('payment_native_option_join')) {
7033                    $data['formType'] = Configure::read('payment_native_option_monthly_payment');
7034                    $ptpp['paymentAmount'] = $nativeOptionPayment;
7035                    if ($userData['unli_native_personal_card_flg'] == 1) {
7036                        $updateIndividualCardFlgParams['individual_card_fail_flg'] = 0;
7037                        $individualUserUpdate['unli_native_personal_card_flg'] = 0;
7038                        $individualUserUpdate['native_option'] = 0;
7039                        $individualUserUpdate['callan_option'] = 0;
7040                        
7041                        $nativeOptionChanged = 1;
7042                    }
7043                    if (!$this->_error_log_set($data, $ptpp)) {
7044                        $this->log(__METHOD__ . ' Failed to save payment data. ' . json_encode($userUpdate), $logFileName);
7045                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data.', $data);
7046                        return ;
7047                    }
7048                }
7049
7050                if ($callanOptionPayment > 0 && $formType != Configure::read('payment_callan_option_join')) {
7051                    $data['formType'] = Configure::read('payment_callan_option_monthly_payment');
7052                    $ptpp['paymentAmount'] = $callanOptionPayment;
7053                    if ($userData['unli_callan_personal_card_flg'] == 1) {
7054                        $updateIndividualCardFlgParams['individual_card_fail_flg'] = 0;
7055                        $individualUserUpdate['unli_callan_personal_card_flg'] = 0;
7056                        $individualUserUpdate['native_option'] = 0;
7057                        $individualUserUpdate['callan_option'] = 0;
7058
7059                        $callanOptionChanged = 1;
7060                    }
7061                    if (!$this->_error_log_set($data, $ptpp)) {
7062                        $this->log(__METHOD__ . ' Failed to save payment data. ' . json_encode($userUpdate), $logFileName);
7063                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data.', $data);
7064                        return ;
7065                    }
7066                }
7067
7068                $this->User->validate = array();
7069                if (!$this->User->read(array_keys($individualUserUpdate), $userId)) {
7070                    $this->log(__METHOD__ . ' User does not exist. --> ' . json_encode($userData), $logFileName);
7071                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'User does not exist.', $data);
7072                    return ;
7073                }
7074
7075                $this->User->set($individualUserUpdate);
7076                if (!$this->User->save()) {
7077                    $this->log(__METHOD__ . ' Failed to update user data. ' . json_encode($individualUserUpdate), $logFileName);
7078                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update user data.', $data);
7079                    return ;
7080                }
7081
7082                // NJ-23781- update individual_card_fail_flg : fail
7083                $res_update_card_fail_flg = $this->update_card_fail_flg($updateIndividualCardFlgParams);
7084
7085                $ptStatus = 2; // error;
7086
7087                // log user option changes
7088                $optionLogParams = [
7089                    'user_id' => $userData['id'],
7090                    'platform' => Configure::read('platform.pclp'),
7091                    'status' => 3, // unsubscribed
7092                    'controller_name' => $this->request->params['controller'],
7093                    'action_name' => $this->request->params['action'],
7094                    'user_type' => 0, // user
7095                    'option_before' => 1,
7096                    'option_after' => '', // turn off
7097                    'option_after_name' => '', // turn off
7098                    'payment_plan_id' => $userData['payment_plan_id'],
7099                ];
7100
7101                if ($nativeOptionChanged) {
7102                    $optionLogParams['option_before_name'] = 'Native Unlimited Option';
7103                    $optionLogParams['option_type'] = 1;
7104                    ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
7105                }
7106
7107                if ($callanOptionChanged) {
7108                    $optionLogParams['option_before_name'] = 'Callan Unlimited Option';
7109                    $optionLogParams['option_type'] = 2;
7110                    ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
7111                }
7112                
7113            }
7114
7115            // log membership status change
7116            if (isset($ptpp['statusBefore']) && isset($ptpp['statusAfter']) && isset($ptpp['platform'])) {
7117                $statusAfter = $kbResultOk ? $ptpp['statusAfter'] : myTools::getCorporateUserMembershipStatusName(UserTable::getEngMembershipTypeData(), $paymentPlanId, true);
7118
7119                $currentUser = $this->User->find('first', array(
7120                    'fields' => array('User.parent_id', 'User.currency_code', 'User.payment_plan_id'),
7121                    'conditions' => array('User.id' => $userId),
7122                    'recursive' => -1
7123                ));
7124
7125                $currency_after_payment = $currentUser['User']['currency_code'];
7126                $plan_id_after_payment = $currentUser['User']['payment_plan_id'];
7127                $parentIdPay = $currentUser['User']['parent_id'];
7128                $is_cron_pay = 0;
7129                if (php_sapi_name() == 'cli'){
7130                    $is_cron_pay = 1;
7131                } 
7132                $usclData = array(
7133                    'user_id' => $userId,
7134                    'platform' => $ptpp['platform'] ?? '',
7135                    'card_company_before' => $userData['card_company'],
7136                    'status_before' => $ptpp['statusBefore'],
7137                    'status_after' => $statusAfter,
7138                    'controller_name' => $this->request->params['controller'],
7139                    'action_name' => $this->request->params['action'],
7140                    'parent_id' => $parentIdPay,
7141                    'is_cron' => $is_cron_pay,
7142                    'currency_before' => $currency_before_payment,
7143                    'currency_after' => $currency_after_payment,
7144                    'payment_plan_id_before' => $plan_id_before_payment,
7145                    'payment_plan_id_after' => $plan_id_after_payment
7146                );
7147
7148                // save user change membership status
7149                if (!$this->UserStatusChangeLog->saveLog($usclData)) {
7150                    $this->log(__METHOD__ . ' Failed to save user status change log data. --> ' . json_encode($paymentData), $logFileName);
7151                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save user status change log data.', $data);
7152                    return;
7153                }
7154            }
7155
7156            // update payment transaction
7157            $this->updatePaymentTransaction(array(
7158                'id' => $ptData['id'],
7159                'fields' => array(
7160                    'status' => $ptStatus,
7161                    'response_text' => array('zp_kickback' => $data)
7162                ),
7163                'logFileName' => 'debug'
7164            ));
7165
7166
7167            // send event to adjust
7168            if ($kbResultOk) {
7169                $adjustParams = array(
7170                    'formType' => $formType,
7171                    'statusBefore' => isset($ptpp['statusBefore']) ? $ptpp['statusBefore'] : null,
7172                    'userId' => $userId,
7173                    'idfa' => $userData['idfa']
7174                );
7175                UserTable::sendEventToAdjust($adjustParams);
7176            }
7177        }
7178
7179        return;
7180    }
7181
7182    /**
7183     * @api {get} /payment/update_card_fail_flg/:user_data/:form_type/:individual_card_fail_flg update_card_fail_flg
7184     * @apiName update_card_fail_flg
7185     * @apiGroup Payment
7186     * @apiDescription This endpoint is used to update card fail flag.
7187     * 
7188     * @apiParam {String} user_data User data. null if not provided
7189     * @apiParam {String} form_type Form type. null if not provided
7190     * @apiParam {Number} individual_card_fail_flg Individual card fail flag. 0 if not provided
7191     * 
7192     * @apiSuccess {Boolean} true Returns true if successful
7193     * 
7194     * @apiError {Boolean} false Returns false if failed
7195     * 
7196     * @apiSuccessExample Success Response:
7197     * true
7198     * 
7199     * @apiErrorExample Error Response:
7200     * false
7201     */
7202    public function update_card_fail_flg($params = []){
7203        $user_data = !empty($params['user_data']) ? $params['user_data'] : null;
7204        $form_type = !empty($params['form_type']) ? $params['form_type'] : null;
7205        $individual_card_fail_flg = !empty($params['individual_card_fail_flg']) ? $params['individual_card_fail_flg'] : 0;
7206        
7207        if(!$user_data || !$form_type){return false;}
7208
7209        $userObj = new UserTable($user_data);
7210
7211        if(in_array($userObj->getMembershipTypeIndex(), Configure::read('corp_personal_card_payment_valid_memberships'))
7212            && in_array($form_type,
7213            array(
7214                Configure::read('payment_credit_textbook_purchase'),
7215                Configure::read('payment_credit_coin_purchase'),
7216                Configure::read('payment_native_option_join'),
7217                Configure::read('payment_credit_receivable'),
7218                Configure::read('payment_credit_appreciation_receivable'),
7219                Configure::read('corporate_credit_card_registration'),
7220                Configure::read('corp_user_change_personal_card')
7221            ))
7222        ){
7223            // - update individual_card_fail_flg
7224            $this->UsersDetail->updateCorpIndividualCardFlg(['user_id' => $userObj->id, 'individual_card_fail_flg' => $individual_card_fail_flg]);
7225            return true;
7226        }
7227
7228        return false;
7229    }
7230
7231    // NJ-69193 ~ private to public to easily access via unit test
7232    public function _error_log_set($data = array(), $paymentParams = array()) {
7233        // set the variables
7234        $userId = isset($data['user_id']) ? $data['user_id'] : 0;
7235        $money = isset($paymentParams['paymentAmount']) ? $paymentParams['paymentAmount'] : ( isset($_GET['money']) ? $_GET['money'] : 0 );
7236        $sendId = isset($data['sendid']) ? $data['sendid'] : 0;
7237        $cardCompany = isset($data['metadata']['card_company']) ? $data['metadata']['card_company'] : Configure::read('card_company.zeus');
7238        $formType = isset($data['formType']) ? $data['formType'] : 0;
7239        $result = array();
7240
7241        if ($userId && !$sendId) {
7242            $sendId = $userId;
7243        } elseif ($sendId && !$userId) {
7244            $userId = $sendId;
7245        }
7246
7247        $paymentType = isset($paymentParams['paymentType']) ? $paymentParams['paymentType'] : null;
7248        $priceId = isset($paymentParams['priceId']) ? $paymentParams['priceId'] : null;
7249        $paymentId = isset($paymentParams['paymentPlanId']) ? $paymentParams['paymentPlanId'] : null;
7250        $currencyCode = isset($paymentParams['currencyCode']) ? $paymentParams['currencyCode'] : Configure::read('currency_jpy');
7251        $discounted_amount = isset($paymentParams['discounted_amount']) ? $paymentParams['discounted_amount'] : 0;
7252
7253        // Check receivable type
7254        $cronDateRun = date("Y-m-d H:i:s");
7255        $receivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun);
7256        $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('appreciation_data.payment_element_type'));
7257        $liveReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.live'));
7258        $receivableFormTypeArr = array( Configure::read('payment_credit_receivable') );
7259        
7260        if( in_array( $formType, $receivableFormTypeArr ) ) {
7261            // Appreciation 
7262            if( $appreciationReceivable > 0 ) {
7263                $this->Payment->create();
7264                $this->Payment->set(array(
7265                    'user_id' => $userId,
7266                    'type_id' => 1,
7267                    'pay_kbn' => 1,
7268                    'form_type' => Configure::read('payment_credit_appreciation_receivable'),
7269                    'reference_id' => $sendId,
7270                    'amount' => $appreciationReceivable,
7271                    'card_company' => $cardCompany,
7272                    'param1' => json_encode($data),
7273                    'param2' => "error:" . $data['error_code'],
7274                    'currency_code' => $currencyCode,
7275                    'price_id' => $priceId,
7276                    'payment_id' => $paymentId,
7277                    'payment_type' => $paymentType,
7278                    'discounted_amount' => $discounted_amount
7279                ));
7280                $result[$formType][] = $this->Payment->save();
7281            }
7282
7283            // Live receivable 
7284            if( $liveReceivable > 0 ) {
7285                $this->Payment->create();
7286                $this->Payment->set(array(
7287                    'user_id' => $userId,
7288                    'type_id' => 1,
7289                    'pay_kbn' => 1,
7290                    'form_type' => Configure::read('payment_live_lesson_receivable'),
7291                    'reference_id' => $sendId,
7292                    'amount' => $liveReceivable,
7293                    'card_company' => $cardCompany,
7294                    'param1' => json_encode($data),
7295                    'param2' => "error:" . $data['error_code'],
7296                    'currency_code' => $currencyCode,
7297                    'price_id' => $priceId,
7298                    'payment_id' => $paymentId,
7299                    'payment_type' => $paymentType,
7300                    'discounted_amount' => $discounted_amount
7301                ));
7302                $res = $this->Payment->save();
7303
7304                if (!$res) {
7305                    CakeLog::debug(__METHOD__ . 'Error : saving live receivable -> params' . json_encode([$data, $paymentParams]));
7306                }
7307                $result[$formType][] = $res;
7308            }        
7309
7310            // Reservation
7311            if( $receivable > 0 ) {
7312                $this->Payment->create();
7313                $this->Payment->set(array(
7314                    'user_id' => $userId,
7315                    'type_id' => 1,
7316                    'pay_kbn' => 1,
7317                    'form_type' => Configure::read('payment_credit_receivable'),
7318                    'reference_id' => $sendId,
7319                    'amount' => $receivable,
7320                    'card_company' => $cardCompany,
7321                    'param1' => json_encode($data),
7322                    'param2' => "error:" . $data['error_code'],
7323                    'currency_code' => $currencyCode,
7324                    'price_id' => $priceId,
7325                    'payment_id' => $paymentId,
7326                    'payment_type' => $paymentType,
7327                    'discounted_amount' => $discounted_amount
7328                ));
7329                $result[$formType][] = $this->Payment->save();
7330            }
7331
7332        } else {
7333            try {
7334                if( $money > 0 ) {
7335                    // save new payment row
7336                    $this->Payment->create();
7337                    $this->Payment->set(array(
7338                            'user_id' => $userId,
7339                            'type_id' => 1,
7340                            'pay_kbn' => 1,
7341                            'form_type' => $formType,
7342                            'reference_id' => $sendId,
7343                            'amount' => $money,
7344                            'card_company' => $cardCompany,
7345                            'param1' => json_encode($data),
7346                            'param2' => "error:" . $data['error_code'],
7347                            'currency_code' => $currencyCode,
7348                            'price_id' => $priceId,
7349                            'payment_id' => $paymentId,
7350                            'payment_type' => $paymentType,
7351                            'discounted_amount' => $discounted_amount
7352                    ));
7353    
7354                    $result[$formType] = $this->Payment->save();
7355    
7356                    $annualDiscountOption = isset($paymentParams['annualDiscountOption']) ? $paymentParams['annualDiscountOption'] : [];
7357                    // check if user plan has annual discount option
7358                    if ($annualDiscountOption) {
7359                        // set data for discount option settlement history
7360                        $doshData = [
7361                            'user_id' => $userId,
7362                            'discount_option_term_id' => $annualDiscountOption['discount_option_term_id'],
7363                            'discount_option_id' => $annualDiscountOption['discount_option_id'],
7364                            'payment_id' => $this->Payment->id,
7365                            'discount_option_price_id' => $annualDiscountOption['discount_option_price_id'],
7366                            'payment_id' => $this->Payment->id,
7367                            'event' => $annualDiscountOption['dosh_event'],
7368                            'amount' =>  $annualDiscountOption['amount'] ?? 0,
7369                            'currency_code' => $currencyCode,
7370                            'type' => isset($annualDiscountOption['dosh_type']) ? $annualDiscountOption['dosh_type'] : null,
7371                            'status' => $annualDiscountOption['dosh_status'],
7372                            'settlement_status' => 0 // failed
7373                        ];
7374    
7375                        // create discount option settlement history
7376                        if (!$res = $this->DiscountOptionsSettlementHistory->createHistory($doshData)) {
7377                        }
7378    
7379                        $result[$formType][] = $res;
7380                    }
7381                }
7382            } catch (\Throwable $th) {
7383                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'try-catch - Failed to create payment receivable.', [
7384                    'data' => $data,
7385                    'payment_transaction' => $paymentParams,
7386                    'error' => $th->getMessage()
7387                ]);
7388            } catch(\Exception $e) {
7389                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'try-catch - Failed to create payment receivable.', [
7390                    'data' => $data,
7391                    'payment_transaction' => $paymentParams,
7392                    'error' => $e->getMessage()
7393                ]);
7394            }
7395        }
7396    
7397        return $result;
7398        
7399    }
7400    /**
7401     * @api {post} /payment/free_digest_member_t_start/:param free_digest_member_t_start
7402     * @apiName free_digest_member_t_start
7403     * @apiGroup Payment
7404     * @apiDescription This endpoint is used to start free digest member.
7405     * 
7406     * @apiParam {String} param Parameter. FALSE if not provided
7407     * 
7408     * @apiBody {String} card_brand Card brand
7409     * 
7410     * @apiSuccess {View} Redirect Redirects to {{ENV}}/payment/payment_credit_retry_form
7411     * 
7412     * @apiError {Boolean} err Returns true if there is error
7413     * 
7414     * @apiSuccessExample Success Response:
7415     * Redirects to {{ENV}}/payment/payment_credit_retry_form
7416     * 
7417     * @apiErrorExample Error Response:
7418     * true
7419     * 
7420     * @apiSampleRequest off
7421     */
7422    public function free_digest_member_t_start($param = FALSE){
7423        $this->checkUser(Configure::read('payment_credit_retry'));
7424        $err = false;
7425        if ($this->request->is('post')) {
7426            if (!isset($this->request->data['card_brand'])) {
7427                $err = true;
7428            } else {
7429                $this->redirect(myTools::getUrl() . '/payment/payment_credit_retry_form/' . $this->request->data['card_brand']);
7430            }
7431        }
7432        $this->set('hide_err', $err);
7433    }
7434
7435    /**
7436     * @api {post} /payment/coupon_form coupon_form
7437     * @apiName coupon_form
7438     * @apiGroup Payment
7439     * @apiDescription This endpoint is used to handle the submission of a complimentary code form.
7440     * 
7441     * @apiSuccess {Boolean} status The status of the request
7442     * @apiSuccess {String} url The URL to redirect to
7443     * 
7444     * @apiError {Boolean} status The status of the request.
7445     * @apiError {String} url The URL to redirect to if the request is unsuccessful.
7446     * 
7447     * @apiSuccessExample {json} Success Response:
7448     * {
7449     *         "status": true,
7450     *         "url": "payment/coupon_code"
7451     * }
7452     * 
7453     * @apiErrorExample {json} Error Response:
7454     * {
7455     *         "status": false,
7456     *         "url": null
7457     * }
7458     */
7459    public function coupon_form(){
7460        $this->response->disableCache();
7461        # Preventing from rendering the 404 not found page error
7462        $this->autoRender = false;
7463
7464        # response data
7465        $response = array(
7466            "status" => false, 
7467            "url" => null
7468        );
7469
7470        # Get register2 data from set session in create_account
7471        $data = $this->Session->read('register2');        
7472
7473        # Get user information
7474        $this->User->openDBReplica();
7475        $data = $this->User->find("first",array(
7476                "conditions" => array('User.id' => $this->Auth->User('id')),
7477                "fields" => array(
7478                    'User.id',
7479                    'User.currency_code',
7480                    'User.payment_plan_id',
7481                    'User.price_id'
7482                ),
7483                "recursive" => -1
7484            )
7485        );
7486        $this->User->closeDBReplica();
7487
7488        $this->PaymentPlanPrice->openDBReplica();
7489        $ccPayment = $this->PaymentPlanPrice->getPaymentData(array(
7490            "currencyCode" => $data['User']["currency_code"],
7491            "paymentPlanId" => Configure::read('payment_plans.complimentary_plan')
7492        ));
7493        $this->PaymentPlanPrice->closeDBReplica();
7494
7495        # check if the request is not post
7496        if (!$this->request->is("post")) {
7497            $response["status"] = false;
7498            return json_encode($response);
7499        }
7500
7501        # get post data
7502        $post = $this->request->data;
7503        $complimentaryCode = trim($post['complimentary_code']);
7504
7505        # check if the post is an empty
7506        if($complimentaryCode === ""):
7507            $response["status"] = true;
7508            return json_encode($response);
7509        endif;
7510
7511        # check if the array is empty on the paymentPlanPrice
7512        if(empty($ccPayment)):
7513            $response["status"] = false;
7514            return json_encode($response);
7515        endif;
7516        
7517        $ccUpdateFlg = $this->User->checkComplimentaryCodeAvailableAndSave(array(
7518            "complimentaryCode" => $complimentaryCode,
7519            "userId" => $data['User']["id"]
7520        ));
7521
7522        # set complimentary error to true if not save
7523        if (!$ccUpdateFlg) {
7524            $response["status"] = false;
7525            return json_encode($response);
7526        } 
7527
7528        $paymentPlanId = (isset($ccPayment['paymentPlanId']) && isset($complimentaryCode)) ? $ccPayment['paymentPlanId'] : null;
7529        $priceId = (isset($ccPayment['priceId']) && isset($complimentaryCode)) ? $ccPayment['priceId'] : null;
7530
7531        if (!isset($ccUpdateFlg) || (isset($ccUpdateFlg) && $ccUpdateFlg)) {
7532
7533            $this->User->openDBReplica();
7534            $dataUpdate = $this->User->find("first",array(
7535                    "conditions" => array('User.id' => $data['User']['id']),
7536                    "fields" => array(
7537                        "User.complimentary_code"
7538                    ),
7539                    "recursive" => -1
7540                )
7541            );
7542            $this->User->closeDBReplica();
7543            $userUpdate = $dataUpdate['User'];        
7544            if (isset($userUpdate["complimentary_code"]) && $userUpdate["complimentary_code"] != $complimentaryCode) {
7545                $this->ComplimentaryCode->updateAll(
7546                    array("account_used_cnt" => "account_used_cnt - 1"),
7547                    array("code" => $complimentaryCode)
7548                );
7549            }
7550
7551            if (!empty($complimentaryCode)) {                
7552                $coinData = array(
7553                    "status" => false,
7554                    "ref" => $data['User']["id"]
7555                );
7556
7557                $this->Session->write("coinReadRefStatus", $coinData);
7558
7559                $response["status"] = true;
7560                $response["url"] = "payment/coupon_code";
7561                $this->Session->write('complimentaryToPlan', true);
7562
7563                # update the complimentary
7564                $updateUserData = array(
7565                    'user_id' => $data['User']['id'],
7566                    'complimentary_code' => $complimentaryCode,
7567                    'payment_plan_id' => $paymentPlanId,
7568                    'price_id' => $priceId,                
7569                );
7570
7571                $this->User->regist($updateUserData);        
7572            }
7573        }
7574        return json_encode($response);
7575    }
7576
7577    /**
7578     * @api {get} /:language/payment/payment_credit_register payment_credit_register()
7579     * @apiName payment_credit_register
7580     * @apiGroup Payment
7581     * @apiDescription This function is used to display the payment credit register page.
7582     * 
7583     * @apiParam {String} language Language code of the user
7584     * 
7585     * @apiSuccess {View} Render Displays the payment credit register page.
7586     * 
7587     * @apiError {View} Redirect Redirects to {{ENV}}/ if monthly price data does not exist.
7588     * @apiError {View} Redirect Redirects to {{ENV}}/account/sms_authentication if user does not have phone number.
7589     * 
7590     * @apiSuccessExample Success Response:
7591     * Displays the payment credit register page.
7592     * 
7593     * @apiErrorExample Error Response No monthly price data:
7594     * Redirects to {{ENV}}/
7595     * 
7596     * @apiErrorExample Error Response No phone number:
7597     * Redirects to {{ENV}}/account/sms_authentication
7598     * 
7599     * @apiSampleRequest off
7600     */
7601    public function payment_credit_register() {
7602        $this->blockWithdrawnSapuriToS();
7603        $this->disablePageForSapuri();
7604        $this->checkUser(Configure::read('payment_credit_authentication'));
7605
7606        $this->loadModel('PurchaseCoinPrice');
7607        $this->set('bonusCoin', myTools::formatAmount($this->PurchaseCoinPrice->getSignupBonusCoin($this->sharedUserData['User']['currency_code'])));
7608
7609        //- NJ-23812 : redirect to sms authentication 
7610        $_userid = $this->Auth->user('id');
7611        $_user = $this->sharedUserData['User'];
7612        
7613        // NJ-68818: check if payment was charged after challenge already
7614        $this->checkIfChargedAfterChallenge($_userid, 'register');
7615
7616        #chocotto plan data
7617        $chocottoPlanData = $this->PaymentPlanPrice->getPaymentData(array(
7618            'currencyCode' => $_user['currency_code'],
7619            'paymentPlanId' => Configure::read('payment_plans.chocotto_plan'),
7620            'logFileName' => $logFileName ?? 'card_register'
7621        ));
7622
7623        // - set chocotto plan price
7624        $this->set('chocottoMonthlyPrice',$chocottoPlanData['fAmount']);
7625        $this->set('chocottoMonthlyPriceNoTax', myTools::formatAmount($chocottoPlanData['amountConstTaxDeducted']));
7626
7627        //- NJ-27262 : check private page from chocotto
7628        $this->set('enableChocottoPlan', $this->Cookie->read('chocotto_lp'));
7629
7630        //NJ-3882 Require SMS Authentication before Credit Card Registration
7631        $this->PhoneVerifyCheckLog->openDBReplica();
7632        $countTotalVerify = $this->PhoneVerifyCheckLog->find('count',array(
7633            'conditions'=> array(
7634                'user_id' => $this->Auth->user('id'),
7635                'status' => 0
7636            )
7637        ));
7638        $this->PhoneVerifyCheckLog->closeDBReplica();
7639        
7640        if (
7641            empty($_user['facebook_id']) && 
7642            empty($_user['google_id']) &&
7643            empty($_user['line_id']) &&
7644            empty($_user['apple_id']) &&
7645            empty($_user['sms_through_flg']) && 
7646            empty($_user['phone_number']) 
7647        ) {
7648            $this->Session->write('check-step1', true);
7649            $this->Session->write('register_user_id', $_userid);
7650            $this->Session->write('register2', array('user_id' => $_userid));
7651            if (empty($_user['corporate_id'])) { // NJ-36129 Bug fix: Skip SMS Auth for Corporate Users
7652                return $this->redirect('/account/sms_authentication');
7653            }
7654        }
7655
7656        $monthlyPrice ??= '';
7657        
7658        // get monthly price for premium
7659        $pDataDisplay = $this->PaymentPlanPrice->getPaymentData(array(
7660            'currencyCode' => $_user['currency_code'],
7661            'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
7662            'logFileName' => 'card_reregister'
7663        ));
7664
7665        // return to top top page if monthly price data does not exist
7666        if (!$pDataDisplay) {
7667            return $this->redirect('/');
7668        }
7669
7670        $this->set('amount', $pDataDisplay['amount']);
7671        $this->set('monthlyPrice', myTools::formatAmount($pDataDisplay['amount']));
7672        $this->set('monthylyPriceNoTax', myTools::formatAmount($pDataDisplay['amountConstTaxDeducted']));
7673        $this->set('monthlyPriceSymbol',myTools::getCurrencySymbol($_user['currency_code']));
7674
7675        // redirect to zeus if currency is equals to jpy
7676        if ($this->sharedUserData['User']['currency_code'] == Configure::read('default.user_currency')) {
7677            $this->zeus_credit_register($pDataDisplay);
7678        // redirect to wp
7679        } else {
7680            $this->wp_credit_register();
7681        }
7682    
7683        $this->CountryCode->openDBReplica();
7684        $countryCodes = $this->CountryCode->find('all',array(
7685            'fields' => array(
7686                'code',
7687                'country_name'
7688            ),
7689            'order' => 'country_name ASC'
7690        ));
7691        $this->CountryCode->closeDBReplica();
7692        $this->set('countryCodes',$countryCodes);
7693        
7694        $user = new UserTable($this->sharedUserData['User']);
7695        $users_detail = new UsersDetailTable($this->sharedUserData['UsersDetail']);
7696        $this->set('users_detail', $users_detail);
7697        $this->set('user', $user);
7698        $this->set('countTotalVerify',$countTotalVerify);
7699        $this->set('amount', $monthlyPrice);
7700        if ($this->RequestHandler->isMobile()) {
7701            if (!$countTotalVerify &&
7702                !$user->facebook_id &&
7703                !$user->google_id &&
7704                !$user->line_id &&
7705                !$user->apple_id &&
7706                !$user->sms_through_flg
7707            ) {
7708                return $this->redirect('/account/sms_authentication');
7709            }
7710        }
7711        
7712        $userData = $this->sharedUserData['User'];
7713        // NJ-30828: set view to display user's paypal email
7714        $this->setPaypalUser($userData);
7715
7716        // NJ-36129
7717        $sp = Configure::read('registration_platforms.sp');
7718        $pc = Configure::read('registration_platforms.pc');
7719        $platformId = $this->RequestHandler->isMobile() ? $sp : $pc;
7720        $stepKey = Configure::read('registration_steps.credit_card_registration');
7721
7722        $saveStepParams = array(
7723            'user_id' => $_userid,
7724            'step_key' => $stepKey,
7725            'platform' => $platformId
7726        );
7727
7728        ClassRegistry::init('UserRegistrationStatus')->saveStep($saveStepParams);
7729        
7730    }
7731
7732    private function zeus_credit_register($premiumPlanData = []) {
7733        $user = $this->sharedUserData['User'];
7734        $formType = Configure::read('payment_credit_authentication');
7735        $logFileName = 'card_reregister';
7736
7737        // get free trial payment data
7738        $freeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
7739            'currencyCode' => $user['currency_code'],
7740            'paymentPlanId' => Configure::read('payment_plans.free_trial'),
7741            'logFileName' => $logFileName
7742        ));
7743
7744        // - NJ-23812 : reset session for paypal credit register data
7745        if ($this->Session->read('paypalPaymentCreditRegisterData')){
7746            $this->Session->delete('paypalPaymentCreditRegisterData');
7747        }
7748
7749
7750        // - NJ-23812 : reset  
7751        if ($this->Session->read('credit_skip_to_confirmation')){
7752            $this->Session->delete('credit_skip_to_confirmation');
7753        }
7754
7755        if (!$freeTrialData) {
7756            return $this->redirect('/');
7757        }
7758
7759        $annualDiscountOptionData = $this->DiscountOptionsPrice->getPaymentData(['currencyCode' => $user['currency_code'], 'discountOptionId' => Configure::read('discount_option.annual.plan_id')]);
7760        $annualDiscountOptionAmount = $annualDiscountOptionData ? $annualDiscountOptionData['amount'] : 0;
7761        $monthlyPriceWithAnnualDiscount = $premiumPlanData['amount'] - $annualDiscountOptionAmount;
7762        $monthlyPriceWithAnnualDiscountNoTax = $monthlyPriceWithAnnualDiscount / Configure::read('added_tax_percentage');
7763        $monthlyPriceWithAnnualDiscountNoTax = round($monthlyPriceWithAnnualDiscountNoTax);
7764
7765        $this->set('enableAnnualDiscountOption', $annualDiscountOptionData ? true : false);
7766        $this->set('annualDiscountOptionAmount', myTools::formatAmount($annualDiscountOptionAmount));
7767        $this->set('monthlyPriceWithAnnualDiscount', myTools::formatAmount($monthlyPriceWithAnnualDiscount));
7768        $this->set('monthlyPriceWithAnnualDiscountNoTax', myTools::formatAmount($monthlyPriceWithAnnualDiscountNoTax));
7769
7770        // check if post data
7771        if ($this->request->is('post')) {
7772            $data = $this->request->data;
7773
7774            // - check if user selected lite plan (1 = lite , 0 = premium)
7775            $paymentPlanType = (isset($data['ZPaymentFullLogs']['payment_plan_type'])) ? (int) $data['ZPaymentFullLogs']['payment_plan_type'] : 0;
7776
7777            $litefreeTrialData = null;
7778
7779            $_isLitePlanFlg = 0;
7780            $liteFormType = null;
7781            $_isChocottoPlanFlg = 0;
7782            $chocottoFormType = null;
7783
7784            // - if lite plan
7785            if ($paymentPlanType == Configure::read('register_plan_types.light')) {
7786                $_isLitePlanFlg = 1;
7787                $userTable = new UserTable($user);
7788                $membershipTypes = UserTable::getEngMembershipTypeData();
7789                $membershipTypeIndex = $userTable->getMembershipTypeIndex();
7790
7791                // - fetch the lite payment plan 
7792                $litefreeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
7793                    'currencyCode' => $user['currency_code'],
7794                    'paymentPlanId' => Configure::read('payment_plans.light_plan_free'),
7795                    'logFileName' => 'card_reregister'
7796                ));
7797                
7798                // - change the price id and payment plan 
7799                $user['price_id'] = $litefreeTrialData['priceId'];
7800                $user['payment_plan_id'] = $litefreeTrialData['paymentPlanId'];
7801                $user['paymentAmount'] = $litefreeTrialData['amount'];
7802                $user['statusBefore'] = $membershipTypes[$membershipTypeIndex];
7803                $_lightplanFree = Configure::read('membership_type_lightplan_free');
7804                $user['statusAfter'] = $membershipTypes[$_lightplanFree]; // - light plan free
7805
7806                // - set the form type 
7807                $liteFormType = $formType = myTools::getLitePlanUserFormType($litefreeTrialData['paymentPlanId']);
7808
7809                // set transaction error to 1 if failed to create payment transaction
7810                if (!$pt = $this->createPaymentTransaction($formType, $user)) {
7811                    $this->set('transactionError', 1);
7812                }
7813
7814                // - update the payment hash
7815                $data['ZPaymentFullLogs']['paymentHash'] =    $pt['payment_hash'];
7816
7817            //- if chocotto plan
7818            } elseif ($paymentPlanType == Configure::read('register_plan_types.chocotto')) {
7819                $_isChocottoPlanFlg = 1;
7820                $userTable = new UserTable($user);
7821                $membershipTypes = UserTable::getEngMembershipTypeData();
7822                $membershipTypeIndex = $userTable->getMembershipTypeIndex();
7823
7824                // - fetch the chocotto payment plan 
7825                $chocottofreeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
7826                    'currencyCode' => $user['currency_code'],
7827                    'paymentPlanId' => Configure::read('payment_plans.free_trial_chocotto'),
7828                    'logFileName' => 'card_reregister'
7829                ));
7830                
7831                // - change the price id and payment plan 
7832                $user['price_id'] = $chocottofreeTrialData['priceId'];
7833                $user['payment_plan_id'] = $chocottofreeTrialData['paymentPlanId'];
7834                $user['paymentAmount'] = $chocottofreeTrialData['amount'];
7835                $user['statusBefore'] = $membershipTypes[$membershipTypeIndex];
7836                $_chocottoPlanFree = Configure::read('membership_type_chocotto_plan_free');
7837                $user['statusAfter'] = $membershipTypes[$_chocottoPlanFree]; // - chocotto plan free
7838
7839                // - set the form type 
7840                $chocottoFormType = $formType = myTools::getChocottoPlanUserFormType($chocottofreeTrialData['paymentPlanId']);
7841
7842                //- NJ-36141: reset daily lesson time if changed to chocotto plan
7843                $this->UsersDetail->chocottoCampUserDetails($user['id'], true);
7844                
7845                // set transaction error to 1 if failed to create payment transaction
7846                if (!$pt = $this->createPaymentTransaction($formType, $user)) {
7847                    $this->set('transactionError', 1);
7848                }
7849
7850                // - update the payment hash
7851                $data['ZPaymentFullLogs']['paymentHash'] =    $pt['payment_hash'];
7852
7853            // if annual discount option
7854            } elseif ($paymentPlanType == Configure::read('register_plan_types.premium_with_annual_discount_option')) {
7855                // redirect to credit page if annual discount option does not exist or is not enabled
7856                if (!$annualDiscountOptionData) {
7857                    return $this->redirect('/');
7858                }
7859
7860                $annualDiscountOptionData['amount'] = 0; // change amount to 0 since this is a subscription
7861                $annualDiscountOptionData += [
7862                    'dosh_event' => Configure::read('discount_option.dosh_event.annual_discount'),
7863                    'dosh_status' => Configure::read('discount_option.dosh_status.subscription'),
7864                    'option_after_name' => 'Annual Discount Option',
7865                    'option_type' => 3
7866                ];
7867
7868                // update payment transaction (add annual discount option data)
7869                $this->PaymentTransaction->updatePaymentParams(array('paymentHash' => $data['ZPaymentFullLogs']['paymentHash'], 'updateData' => ['discountOption' => $annualDiscountOptionData]));
7870
7871                $data['discountOption'] = $annualDiscountOptionData;
7872            }
7873
7874            // redirect to paypal confirm page if payment gateway selected is paypal
7875            if ($data['payment_gateway_type'] == Configure::read('card_company.paypal')) {
7876                $data['paymentPlanData'] = $freeTrialData;
7877
7878                if ($paymentPlanType == 1) {
7879                    $data['paymentPlanData'] = $litefreeTrialData;
7880                }
7881
7882                $this->Session->write('paypalPaymentCreditRegisterData', $data);
7883                return $this->redirect(myTools::getUrl() . '/payment/paypal_payment_credit_register_confirm');
7884            }
7885
7886            // delete payment gateway type memcache
7887            $this->memcache->delete('creditReregisterPaymentGatewayType_' . $user['api_token']);
7888
7889            $data['ZPaymentFullLogs']['clientip'] = Configure::read('ZEUS_clientip');
7890            $data['ZPaymentFullLogs']['telno'] = Configure::read('credit.default_telno');
7891
7892            if ($this->Session->read('PaymentCreditRegisterInfo')) {
7893                $this->Session->delete('PaymentCreditRegisterInfo');
7894            }
7895            $this->Session->write('PaymentCreditRegisterInfo', $data);
7896
7897            //NJ-13482 Skip Confirmation Page for New Enrollment
7898            //NJ-25522: Skip Confirmation Page if using 3D secure challenge
7899            $zeus3DSecureChallengeFlg = $this->memcache->get('zeus3DSecureChallengeFlg_' . $user['id']);
7900
7901            if (isset($user['id']) && (!$this->isForTrialReenrollment($user['id']) || $zeus3DSecureChallengeFlg)) {
7902                $data = $this->Session->read('PaymentCreditRegisterInfo');
7903                $checkToken = $this->checkToken($data['token']);
7904
7905                if ($checkToken) {
7906                    $this->unsetToken();
7907                    $formType = Configure::read('payment_credit_authentication');
7908                
7909                    if ($_isLitePlanFlg) {
7910                        $formType = $liteFormType;
7911                    }
7912
7913                    if ($_isChocottoPlanFlg) {
7914                        $formType = $chocottoFormType;
7915                    }
7916    
7917                    $referrer = array('controller' => 'Payment', 'action' => 'payment_credit_register');
7918                    $this->z_start($data, $formType, $referrer);
7919                }
7920            }
7921
7922            $this->Session->delete('paypalPaymentCreditRegisterData');
7923
7924            $this->Session->write('credit_skip_to_confirmation',true);
7925
7926            return $this->redirect(myTools::getUrl() . '/payment/payment_credit_register_confirm');
7927
7928        } else {
7929            $data = $this->Session->read('PaymentCreditRegisterInfo');
7930            $this->set('data', $data);
7931        }
7932
7933        // NC-3914
7934        $this->getAndSetCardInfo($user);
7935
7936        // clear previously set tokens and set new token
7937        $this->unsetToken();
7938        $token = md5(uniqid(rand(), true));
7939        $this->Session->write('Payment.token', $token);
7940
7941        $userTable = new UserTable($user);
7942        $membershipTypes = UserTable::getEngMembershipTypeData();
7943        $membershipTypeIndex = $userTable->getMembershipTypeIndex();
7944        
7945        $user['price_id'] = $freeTrialData['priceId'];
7946        $user['payment_plan_id'] = $freeTrialData['paymentPlanId'];
7947        $user['paymentAmount'] = $freeTrialData['amount'];
7948        $user['statusBefore'] = $membershipTypes[$membershipTypeIndex];
7949        $user['statusAfter'] = $membershipTypes[2];
7950
7951        if (isset($annualDiscountOption)) {
7952            $user['discountOption'] = $annualDiscountOption;
7953        }
7954
7955        // set transaction error to 1 if failed to create payment transaction
7956        if (!$pt = $this->createPaymentTransaction($formType, $user)) {
7957            $this->set('transactionError', 1);
7958        }
7959
7960        // ------- NJ-23812 : set support paypal skip from confirmation page 
7961        $sessionPaypalParams = array(
7962            'token' => $token,
7963            'payment_gateway_type' => Configure::read('card_company.paypal'),
7964            'ZPaymentFullLogs' => array(
7965                'paymentHash' => isset($pt['payment_hash']) ? $pt['payment_hash'] : "",
7966                'money' => str_replace('.00', '', $freeTrialData['amount'])
7967            ),
7968            'paymentPlanData' => $freeTrialData
7969        );
7970
7971        $this->Session->write('paypalPaymentCreditRegisterData', $sessionPaypalParams);
7972        
7973        $this->setSupportPayPal($user);
7974        $this->set('token', $token);
7975
7976        $this->set('userApiToken', $this->sharedUserData['User']['api_token']);
7977        $this->set('paypalFlg', true); // use for modal loader
7978
7979        // ----- NJ-23812: end support paypal skip from confirmation page
7980
7981        // nj-23812:support to redirect to profile from coupon
7982        $this->Session->write('register2',array('user_id' => $user['id']));
7983         $this->Session->write('check-step1',true);
7984         $this->Session->write('check-step2',true);
7985        $this->Session->read('register_user_id',$user['id']);
7986
7987        $this->set('cardLogo', myTools::getWorldpayCardLogo($user['card_brand']));
7988        $this->set('zeusTransactionFlag', true);
7989        $this->set('paymentHash', $pt['payment_hash']);
7990        $this->set('amount', str_replace('.00', '', $freeTrialData['amount']));
7991        $this->set('currencyCode', $user['currency_code']);
7992        $this->set('formType', $formType);
7993        $this->setPaymentViewVars();
7994
7995        // - NJ-18780 : set payment vars
7996        $this->setLitePaymentInfoView($user,true,true);
7997
7998        if ($this->RequestHandler->isMobile()) {
7999            $this->set('isSPView', true);
8000            $this->set('userApiToken', $user['api_token']);
8001        }
8002
8003        $renderParam = array(
8004            'forceMobile' => true,
8005            'this' => $this,
8006            'spView' => '/Mobile/Payment/payment_credit_register',
8007            'layout' => 'mobile'
8008        );
8009
8010        myTools::render($renderParam);
8011    }
8012    
8013    private function checkIfChargedAfterChallenge($userId, $fromAction) {
8014        if (!$userData = $this->sharedUserData['User']) {
8015            return $this->redirect(myTools::getUrl() . '/');
8016        }
8017
8018        if (!class_exists('myMemcached')) {
8019            App::uses('myMemcached', 'Lib');
8020        }
8021
8022        $myMemcachedVar = new myMemcached();
8023
8024        // get zeus challenge flag
8025        $zeus3DSecureChallengeFlg = $myMemcachedVar->get('zeus3DSecureChallengeFlg_' . $userId);
8026
8027        if ($zeus3DSecureChallengeFlg) {
8028            $zeus3DSecurePaymentSuccessFlg = $myMemcachedVar->get('zeus3DSecurePaymentSuccessFlg_' . $userId);
8029            $response = !empty($zeus3DSecurePaymentSuccessFlg) && $zeus3DSecurePaymentSuccessFlg == 'OK' ? 'Success_order' : 'failure_order';
8030            $formType = $myMemcachedVar->get('zeus_3dSecure_challenge_formType_' . $userId);
8031
8032            // clear flag
8033            $myMemcachedVar->delete('zeus3DSecureChallengeFlg_' . $userId);
8034            $myMemcachedVar->delete('zeus_3dSecure_challenge_formType_' . $userId);
8035            $myMemcachedVar->delete('zeus3DSecurePaymentSuccessFlg_' . $userId);
8036        }
8037
8038        if (
8039            (isset($response) && !empty($response)) && 
8040            (
8041                (is_array($response) && is_string($response[0]) && strtolower($response[0]) === "success_order") || 
8042                (is_string($response) && strtolower($response) === "success_order")
8043            )
8044        ) {
8045            // for payment_credit_register checker
8046            if($fromAction == 'register') {
8047                if($this->Session->read('PaymentCreditRegisterInfo')) {
8048                    $this->Session->delete('PaymentCreditRegisterInfo');
8049                }
8050                
8051                if(!class_exists('myMailer')) {
8052                    App::uses('myMailer', 'Lib');
8053                }
8054                $mail_id = Configure::read('site_in_mail.student_registration_complete');
8055                if ($userData &&  !in_array($userData['currency_code'], Configure::read('global_free_trail_currencies') ) ) {
8056                    $mail_id = Configure::read('site_in_mail.registration_no_trial_currencies');
8057                }
8058                myMailer::sendTemplateMail($mail_id, $userData['email'], $userData, array(), 'User');
8059                //NJ-13482
8060                $this->Session->write('payment_credit_register_complete', true);
8061                return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_register_complete'));
8062
8063            // for payment_credit_charge checker
8064            } elseif($fromAction == 'rejoin') {
8065                if($this->Session->read('PaymentCreditChargeInfo')) {
8066                    $this->Session->delete('PaymentCreditChargeInfo');
8067                }
8068
8069                $action = 'payment_credit_charge_complete';
8070                // if complimentary plan user before
8071                if ($this->memcache->get('com_plan_user_'.$userData['id'])) {
8072                    $this->memcache->delete('com_plan_user_'.$userData['id']);
8073                    $action = 'coupon_payment_credit_charge_complete';
8074                }
8075
8076                // Teacher Perks : Student re-enroll
8077                if ( $formType == Configure::read('payment_credit_force_charge')) {
8078                    ClassRegistry::init('TeacherPerksAccount')->reEnroll(['user_id' => $userData['id']]);
8079                }
8080                
8081                //    NC-7644 Add code reward for re-enroolling with the campaign code
8082                $this->log(__METHOD__ ."sai_debug -> Add 500 Coin Reward for re-enroll: ", "error");
8083                $this->addCoinRewardForReenroll($userData);
8084
8085                // - add monthly mc coin if lite plan user 
8086                if ($formType == Configure::read('payment_lite_credit_paid')) {
8087                    $this->liteUserAddCoinRewardForReenroll(array('id' => $userData['id']));
8088                }
8089                
8090                return $this->redirect(array('controller' => 'payment', 'action' => $action));
8091
8092            // for payment_credit_retry checker
8093            } elseif($fromAction == 'retry') {
8094                if($formType == Configure::read('payment_credit_retry')) {
8095                    if($this->Session->read('PaymentCreditRetryInfo')) {
8096                        $this->Session->delete('PaymentCreditRetryInfo');
8097                    }
8098
8099                    if($this->Session->read('PaymentCreditRetryInfoCorporateAmount')) {
8100                        $this->Session->delete('PaymentCreditRetryInfoCorporateAmount');
8101                    }
8102
8103                    // - flag manual paying user success
8104                    UserTable::saveManualPayingUsersToMemcache($userData['id']);
8105                    return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_retry_complete'));
8106                }
8107
8108            // for payment_credit_change checker
8109            } elseif($fromAction == 'payment_change') {
8110                $requestData = $this->request->query;
8111
8112                if(isset($requestData) && !empty($requestData)) {
8113                    if ( isset($requestData['page_origin']) ) {
8114                        if ( isset($requestData['page_origin']) && $requestData['page_origin'] == 1 ) { // Store
8115                            $url = "page_origin=".$requestData['page_origin'];
8116                        } elseif (isset($requestData['page_origin']) && $requestData['page_origin'] == 2) { // Ebook
8117                            $url = "page_origin=".$requestData['page_origin'];
8118                        }
8119                    }
8120                }
8121
8122                if (isset($url) && !empty($url)) {
8123                    return $this->redirect(array('controller' => 'store', 'action' => 'card_register_complete','?' => $url));
8124                } else{
8125                    return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_change_complete'));
8126                }
8127            }
8128        }
8129    }
8130
8131    private function wp_credit_register() {
8132        // set variables
8133        $user = $this->sharedUserData['User'];
8134        $apiToken = $user['api_token'];
8135        $memKey = "pc_wp_register_card_type_{$apiToken}";
8136        $memData = $this->memcache->get($memKey);
8137        $cardType = isset($memData['cardType']) ? $memData['cardType'] : 0;
8138
8139        // get free trial plan payment data
8140        $freeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
8141            'currencyCode' => $user['currency_code'],
8142            'paymentPlanId' => Configure::read('payment_plans.free_trial'),
8143            'logFileName' => 'card_reregister'
8144        ));
8145
8146
8147        // - NJ-23812
8148        if ($this->Session->read('credit_skip_to_confirmation')) {
8149            $this->Session->delete('credit_skip_to_confirmation');
8150        }
8151
8152
8153        // - NJ-23812:  add session to allow to profile page and coupon
8154        if (isset($user['User'])){
8155            $this->Session->write('register2',array('user_id' => $user['User']['id']));
8156            $this->Session->read('register_user_id',$user['User']['id']);
8157        }
8158         $this->Session->write('check-step1',true);
8159         $this->Session->write('check-step2',true);
8160
8161        $isCardRegistered = false;
8162        if (    
8163            (!empty($user['card_brand']) && !empty($user['card_number'])) 
8164        ) {
8165            $isCardRegistered = true;
8166        }
8167
8168        // redirect to mypage if free trial plan payment is not supported
8169        if (!$freeTrialData) {
8170            return $this->redirect('/');
8171        }
8172
8173        if ($this->request->is('post')) {
8174            $cardType = $this->request->data['cardType'];
8175
8176            // memcache card type value
8177            $this->memcacheCardType(array(
8178                'key' => $memKey,
8179                'value' => array('cardType' => $cardType)
8180            ));
8181
8182            // redirect to hosted page if using new card ($cardType = 1)
8183            if ($cardType) {
8184                return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/payment/wp_credit_register_form");
8185            // redirect to confirm page if using existing card ($cardType = 0)
8186            } else {
8187
8188                // - NJ-23812: write session to skip and auto charge 
8189                $this->Session->write('credit_skip_to_confirmation',true);
8190
8191
8192                return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/payment/payment_credit_register_confirm");
8193            }
8194        }
8195
8196        /* check if there is error during payment process */
8197        if ($errorType = isset($this->request->query['wpErrType']) ? $this->request->query['wpErrType'] : null) {
8198            if ($error = myTools::getWorldpayErrorMsg($errorType)) {
8199                $this->set('error', $error);
8200            }
8201        } else {
8202            $memErrorKey = 'pc_wp_register_error_'. $apiToken;
8203            if ($error = $this->memcache->get($memErrorKey)) {
8204                $this->set('error', $error);
8205
8206                // delete memcache error
8207                $this->memcache->delete($memErrorKey);
8208            }
8209        }
8210
8211        // //if no registered card, redirect to hosted page if using new card ($cardType = 1)
8212        // if (!$isCardRegistered) {
8213        //     // memcache card type value
8214        //     $this->memcacheCardType(array(
8215        //         'key' => $memKey,
8216        //         'value' => array('cardType' => 1)
8217        //     ));
8218        //     return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/payment/wp_credit_register_form");
8219        // }
8220
8221        if (!$isCardRegistered) {
8222            $cardType = 1;
8223        }
8224
8225
8226        // - NJ-23812 
8227        $formType = Configure::read('payment_credit_authentication');
8228        $_user = new UserTable($this->sharedUserData['User']);
8229
8230        // check if allowed aftee
8231        $this->checkAfteeSupported($this->sharedUserData['User'],true);
8232
8233        if ($this->RequestHandler->isMobile()) {
8234
8235            //NJ-3882 Require SMS Authentication before Credit Card Registration
8236            $this->PhoneVerifyCheckLog->openDBReplica();
8237            $countTotalVerify = $this->PhoneVerifyCheckLog->find('count',array(
8238                'conditions'=> array(
8239                    'user_id' => $this->Auth->user('id'),
8240                    'status' => 0
8241                )
8242            ));
8243            $this->PhoneVerifyCheckLog->closeDBReplica();
8244            $this->set('countTotalVerify',$countTotalVerify);
8245
8246            $this->set('user',new UserTable($this->sharedUserData['User']));
8247
8248        }else{
8249            $this->set('user', $_user);
8250        }
8251
8252        // - set view vars
8253        $this->set('pmtValue', 'auth');
8254        $this->set('apiToken', $apiToken);
8255        $this->set('logFileName', 'card_reregister');
8256        $this->set('nc_terminal_type', 1); // pc
8257        $this->set('memKeyError', 'pc_wp_register_error_' . $apiToken);
8258        $this->set('formType', $formType);
8259        $this->set('referrer', urlencode(myTools::getUrl() . "/{$this->localizeDir}/payment/payment_credit_register"));
8260        $this->set('successUrl', urlencode(myTools::getUrl() . "/{$this->localizeDir}/payment/payment_credit_register_complete"));
8261        $this->set('isCardRegistered',$isCardRegistered);
8262        // // - end NJ-23812
8263        
8264
8265        // - NJ-23812: display premium data 
8266        $currencyCode = $user['currency_code'];
8267        $premiumData = $this->PaymentPlanPrice->getPaymentData(array(
8268            'currencyCode' => $currencyCode,
8269            'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
8270            'logFileName' => 'card_reregister'
8271        ));
8272
8273        $currencyData = $this->Currency->getSymbolAndPosition($currencyCode);
8274
8275        $this->set('monthlyPrice', myTools::formatAmount($premiumData['amount']));
8276        $this->set('monthylyPriceNoTax', myTools::formatAmount($premiumData['amountConstTaxDeducted']));
8277        $this->set('monthlyPriceSymbol',myTools::getCurrencySymbol($currencyCode));
8278
8279        // set view variables
8280        $this->set('cardLogo', myTools::getWorldpayCardLogo($user['card_brand']));
8281        $this->set('cardType', $cardType);
8282        $this->set('cardBrand', $user['card_brand']);
8283        $this->set('cardNumber', $user['card_number']);
8284        $this->render('/Payment/wp_payment_credit_register');
8285
8286        $renderParam = array(
8287            'forceMobile' => true,
8288            'this' => $this,
8289            'spView' => '/Mobile/Payment/wp_payment_credit_register',
8290            'layout' => 'mobile'
8291        );
8292
8293        myTools::render($renderParam);
8294    }
8295    /**
8296     * @api {get} /:language/payment/payment_credit_register_confirm payment_credit_register_confirm()
8297     * @apiName payment_credit_register_confirm
8298     * @apiGroup Payment
8299     * @apiDescription This function is used to display the credit card registration confirmation page.
8300     * 
8301     * @apiParam {String} language Language code of the user
8302     * 
8303     * @apiSuccess {View} Render Displays the credit card registration confirmation page.
8304     * @apiSuccess {View} Redirect Redirects to zeus credit register confirm function if currency is equals to jpy.
8305     * @apiSuccess {View} Redirect Redirects towp credit register confirm function if currency is not equals to jpy.
8306     * 
8307     * @apiSuccessExample Success Response:
8308     * Displays the credit card registration confirmation page.
8309     * 
8310     * @apiSuccessExample Success Response Redirect to zeus process if currency is equals to jpy:
8311     * Redirects to zeus_credit_register_confirm function if currency is equals to jpy.
8312     * 
8313     * @apiSuccessExample Success Response Redirect to wp process if currency is not equals to jpy:
8314     * Redirects to wp_credit_register_confirm function if currency is not equals to jpy.
8315     * 
8316     * @apiSampleRequest off
8317     */
8318    public function payment_credit_register_confirm() {
8319        $this->checkUser(Configure::read('payment_credit_authentication'));
8320
8321        // redirect to zeus process if currency is equals to jpy
8322        if ($this->sharedUserData['User']['currency_code'] == Configure::read('default.user_currency')) {
8323            $this->zeus_credit_register_confirm();
8324        // redirect to wp
8325        } else {
8326            $this->wp_credit_register_confirm();
8327        }
8328    }
8329
8330    public function zeus_credit_register_confirm() {
8331        $data = $this->Session->read('PaymentCreditRegisterInfo');
8332        if (!$data) {
8333            return $this->redirect(myTools::getUrl() . '/');
8334        }
8335
8336        $readSkipConfirmation = $this->Session->read('credit_skip_to_confirmation');
8337        if ($readSkipConfirmation){
8338            $this->Session->delete('credit_skip_to_confirmation');
8339        }
8340        $readSkipConfirmation = true;//force to skip confirmation page
8341
8342        if ($this->request->is('post') || $readSkipConfirmation) {
8343            # check if token matches token in session
8344            $checkToken = $this->checkToken($data['token']);
8345            # check if token is true
8346            if ($checkToken) {
8347                # unset previously set tokens
8348                $this->unsetToken();
8349                $formType = Configure::read('payment_credit_authentication');
8350                $referrer = array('controller' => 'Payment', 'action' => 'payment_credit_register');
8351                $this->z_start($data, $formType, $referrer);
8352            }
8353
8354        }
8355
8356        if (isset($data['ZPaymentFullLogs']['cardnumber']) && !empty($data['ZPaymentFullLogs']['cardnumber'])) {
8357            $cardChunks = str_split($data['ZPaymentFullLogs']['cardnumber'], 4);
8358            $this->set('cardNumber', end($cardChunks));
8359        } else {
8360            $this->getAndSetCardInfo($this->sharedUserData['User']);
8361        }
8362
8363        $this->set('data', $data);
8364
8365        $renderParam = array(
8366            'forceMobile' => true,
8367            'this' => $this,
8368            'spView' => '/Mobile/Payment/payment_credit_register_confirm',
8369            'layout' => 'mobile'
8370        );
8371
8372        myTools::render($renderParam);
8373    }
8374
8375    public function wp_credit_register_confirm() {
8376        $this->response->disableCache();
8377        // set variables
8378        $logFileName = 'card_reregister';
8379        $user = $this->sharedUserData['User'];
8380        $currencyCode = $user['currency_code'];
8381        $userId = $user['id'];
8382        $apiToken = $user['api_token'];
8383
8384        $readSkipConfirmation = $this->Session->read('credit_skip_to_confirmation');
8385        if ($readSkipConfirmation) {
8386            $this->Session->delete('credit_skip_to_confirmation');
8387        }
8388
8389        $memKey = "pc_wp_register_card_type_{$apiToken}";
8390        // redirect to mypage if memcache card type is not set
8391        if (!$this->memcache->get($memKey)) {
8392            return $this->redirect('/');
8393        }
8394
8395        if ($this->request->is('post') || $readSkipConfirmation) {
8396            $paymentMethodType = myTools::getWPPaymentMethodType($user['card_brand'], 'auth');
8397            $merchantCode = myTools::getWPMerchantCode($paymentMethodType);
8398            $paymentMethod = explode('_', $paymentMethodType);
8399            $paymentMethod = isset($paymentMethod[0]) ? $paymentMethod[0] : null;
8400            $orderCode = myTools::generateOrderCode($userId);
8401            $currencyExponents = Configure::read('worldpay.currency_exponents');
8402            $exponent = $currencyExponents[$currencyCode];
8403            $nominalAmountArr = myTools::getWorldpayNominalAmountList($paymentMethod, $merchantCode);
8404
8405            // get nominal amount with checking currency exponent
8406            $totalAmountArr = myTools::wpGetAmount($exponent, $nominalAmountArr[$currencyCode]);
8407            $ncAmount = $totalAmountArr['ncAmount'];
8408            $wpAmount = $totalAmountArr['wpAmount'];
8409
8410            // get free trial payment data
8411            $freeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
8412                'currencyCode' => $currencyCode,
8413                'paymentPlanId' => Configure::read('payment_plans.free_trial'),
8414                'logFileName' => $logFileName
8415            ));
8416
8417            // redirect to mypage if free trial plan payment is not supported
8418            if (!$freeTrialData) {
8419                return $this->redirect('/');
8420            }
8421
8422            $user['payment_plan_id'] = $freeTrialData['paymentPlanId'];
8423            $user['price_id'] = $freeTrialData['priceId'];
8424
8425            $wpData = array(
8426                'cardToken' => $user['card_token'],
8427                'merchantCode' => $merchantCode,
8428                'paymentHash' => $orderCode,
8429                'wpPaymentAmount' => $wpAmount
8430            );
8431
8432            // set payment amount
8433            $user['paymentAmount'] = 0;
8434            $formType = Configure::read('payment_credit_authentication');
8435
8436            // create payment transaction
8437            if (!$pt = $this->createPaymentTransaction($formType, $user, $wpData)) {
8438                $this->log(__METHOD__ .' Failed to save payment transaction. Params --> ' . json_encode($wpData), $logFileName);
8439                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to save payment transaction. Params --> ' . json_encode($wpData), 'error');
8440                return $this->redirect('/');
8441            }
8442
8443            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - After save payment transaction. Params --> ' . json_encode($wpData), 'error');
8444
8445            // if aftee payment
8446            if ($user['card_company'] == Configure::read('card_company.aftee') || ($user['card_brand'] == "AFTEE" && !empty($user['aftee_transaction_identifier']))) {
8447
8448                // default result
8449                $checkRes = array(
8450                    'OrderCode' => $orderCode,
8451                    'authentication_token' => $user['card_token'],
8452                    'response' => 'Aftee payment amount is zero',
8453                    'customer' => array(
8454                        'phone_number' =>  $user['phone_number']
8455                    )
8456                );
8457                $receivableResult = json_encode($checkRes);
8458                $afteeTransactionIdentifier = $user['aftee_transaction_identifier'];
8459
8460
8461                if ($user['paymentAmount'] > 0) {
8462
8463                    if (!class_exists('AfteePaymentService')) {
8464                        App::uses('AfteePaymentService','Lib');
8465                    }
8466                    $afteeService = new AfteePaymentService();
8467                    $afteeChecksumData = array(
8468                        'shopItemId' => "AFTEE" . $formType,
8469                        'itemName' => 'CreditRegisterUsingExistingCard',
8470                        'itemPrice' => $user['paymentAmount'],
8471                        'itemCount' => 1,
8472                        'customerPhoneNumber' => $user['phone_number'],
8473                        'customerEmail' => $user['email'],
8474                        'shopTransactionNo' => $orderCode,
8475                        'userID' =>  $user['id']
8476                    );
8477                    $checksum = $afteeService->generateChecksum($afteeChecksumData, false);
8478                    $afteeData = array(
8479                        'authentication_token' => $user['card_token'],
8480                        'related_id' => $user['aftee_transaction_identifier'],
8481                        'checksum' => $checksum['checksum'],
8482                        'shop_transaction_no' => $orderCode,
8483                        'transaction_options' => array(1)
8484                    );
8485            
8486                    $afteePaymentData = array_merge($afteeData, $checksum['settlementData']);
8487        
8488                    // aftee execute payment
8489                    $receivableResult = $afteeService->directPayment($afteePaymentData);
8490                    $checkRes = json_decode($receivableResult, true);
8491
8492
8493                    if ( isset($checkRes['object']) && $checkRes['object'] == 'transaction') {
8494                        $prPaymentSuccess = true;
8495                    } else if ( !array_key_exists("object", $checkRes) || (isset($checkRes['object']) && $checkRes['object'] == 'error')) {
8496                        $prPaymentSuccess = false;
8497                    }
8498
8499                    $afteeTransactionIdentifier = isset($checkRes['id']) && !empty($checkRes['id']) ? $checkRes['id'] : NULL;
8500                    if (isset($checkRes['related_transaction']) && !empty($checkRes['related_transaction'])) {
8501                        $afteeTransactionIdentifier = $checkRes['related_transaction'];
8502                    }
8503                    $orderCode = isset($checkRes['shop_transaction_no']) && !empty($checkRes['shop_transaction_no']) ? $checkRes['shop_transaction_no'] : NULL;
8504                    $checkRes['OrderCode'] = $orderCode;
8505                }
8506
8507                // process payment data
8508                if ($prPaymentSuccess || $user['paymentAmount'] == 0) {
8509                    // set user model
8510                    $uModel = $this->User;
8511                    $dataSource = $uModel->getDataSource();
8512                    $dataSource->begin();
8513
8514                    $afteeParams = array(
8515                        'data' => $checkRes,
8516                        'ptData' => $pt,
8517                        'logFileName' => $logFileName,
8518                        'dataSource' => $dataSource,
8519                        'amount' => $user['paymentAmount'],
8520                        'userData' => $user,
8521                        'transactionIdentifier' => $afteeTransactionIdentifier,
8522                        'aftee' => 1
8523                    );
8524    
8525                    $this->processAfteePayment($afteeParams);
8526                }
8527
8528                // update payment transaction
8529                $updateData = array(
8530                    'id' => $pt['id'],
8531                    'fields' => array(
8532                        'status' => $prPaymentSuccess,
8533                        'response_text' => array('aftee_directPayment_response' => $receivableResult))
8534                );
8535
8536                // update payment transaction
8537                $this->PaymentTransaction->updateAfteePaymentTransaction($updateData);
8538
8539
8540                // redirect to payment_credit_charge with error display if direct payment response is not authorised
8541                if (!$prPaymentSuccess && $user['paymentAmount'] > 0) {
8542                    if (!class_exists('myMemcached')) {
8543                        App::uses('myMemcached', 'Lib');
8544                    }
8545                    $memKeyError = 'pc_wp_register_error_' . $apiToken;
8546                    $memerror = __('トランザクションを完了できません。 もう一度お試しください。');
8547                    $memcached = new myMemcached();
8548                    $memcached->set(array(
8549                        'key' => $memKeyError,
8550                        'value' => $memerror,
8551                        'expire' => 3600 // 1 hour
8552                    ));
8553                    return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/payment/payment_credit_register");
8554                }
8555
8556            } else {
8557
8558                $wpData = array(
8559                    'merchantCode' => $merchantCode,
8560                    'orderCode' => $orderCode,
8561                    'description' => 'Credit Register Using Existing Card',
8562                    'currencyCode' => $currencyCode,
8563                    'exponent' => $exponent,
8564                    'amount' => $wpAmount,
8565                    'cardToken' => $user['card_token'],
8566                    'email' => $user['email'],
8567                    'authenticatedShopperId' => $userId,
8568                    'xmlName' => 'direct_payment_with_token',
8569                    'shopperIpAddress' => $_SERVER["REMOTE_ADDR"],
8570                    'wpTransactionIdentifier' => $user['wp_transaction_identifier'],
8571                    'paymentMethod' => $paymentMethod
8572                );
8573
8574                $result = wpPaymentService::directPayment($wpData);
8575
8576                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - directPayment result --> ' . json_encode($result), 'error');
8577
8578                $updateData = array(
8579                    'id' => $pt['id'],
8580                    'fields' => array('response_text' => array('directPayment_response' => $result)),
8581                    'logFileName' => $logFileName
8582                );
8583
8584                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - before updatePaymentTransaction result --> ' . json_encode($updateData), 'error');
8585
8586                // redirect to retry page if failed to update payment transaction
8587                if (!$this->updatePaymentTransaction($updateData)) {
8588                    return $this->redirect('/');
8589                }
8590
8591                // redirect to wp_credit_register with error display if direct payment response is not authorised
8592                if (!myTools::checkIfWPPaymentResponseIsAuthorised($result)) {
8593                    $params = array(
8594                        'apiToken' => $apiToken,
8595                        'wpResponse' => $result,
8596                        'memKey' => 'pc_wp_register_error_' . $apiToken
8597                    );
8598                    myTools::parseAndSetWPErrorResponse($params);
8599                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - WP Payment not authorised --> ' . json_encode($params), 'error');
8600                    return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/payment/payment_credit_register");
8601                }
8602
8603            }
8604
8605
8606
8607
8608            // delete memcache
8609            if ($this->memcache->get($memKey)) {
8610                $this->memcache->delete($memKey);
8611            }
8612            
8613            // send registration completion email
8614            App::uses('myMailer','Lib');
8615            $mail_id = Configure::read('site_in_mail.student_registration_complete');
8616            if ($user &&  !in_array($user['currency_code'], Configure::read('global_free_trail_currencies') ) ) {
8617                $mail_id = Configure::read('site_in_mail.registration_no_trial_currencies');
8618            }
8619            myMailer::sendTemplateMail($mail_id, $user['email'], $user, array(), 'User');
8620            //NJ-13482
8621            $this->Session->write('payment_credit_register_complete', true);
8622            return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/payment/payment_credit_register_complete");
8623        }
8624
8625        $currencyData = $this->Currency->getSymbolAndPosition($currencyCode);
8626        $this->set('freeTrialPrice', myTools::addPriceSymbol(0, $currencyData['symbol'], $currencyData['prefix_suffix_flg']));
8627
8628        // set view variables
8629        $this->set('cardLogo', myTools::getWorldpayCardLogo($user['card_brand']));
8630        $this->set('cardBrand', $user['card_brand']);
8631        $this->set('cardNumber', $user['card_number']);
8632        $this->set('cardCompany', $user['card_company']);
8633        $this->render('/Payment/wp_payment_credit_register_confirm');
8634
8635        $renderParam = array(
8636            'forceMobile' => true,
8637            'this' => $this,
8638            'spView' => '/Mobile/Payment/wp_payment_credit_register_confirm',
8639            'layout' => 'mobile'
8640        );
8641
8642        myTools::render($renderParam);
8643    }
8644    /**
8645     * @api {get} /:language/payment/paypal_payment_credit_register_confirm paypal_payment_credit_register_confirm()
8646     * @apiName paypal_payment_credit_register_confirm
8647     * @apiGroup Payment
8648     * @apiDescription This function is used to display the credit card registration confirmation page using paypal.
8649     * 
8650     * @apiParam {String} language Language code of the user
8651     * 
8652     * @apiSuccess {View} Render Displays the credit card registration confirmation page using paypal.
8653     * @apiSuccess {View} Render Displays the credit card registration confirmation page using paypal sp version for mobile.
8654     * 
8655     * @apiError {View} Redirect Redirects to {{ENV}}/ missing paypal payment credit register data.
8656     * 
8657     * @apiSuccessExample Success Response PC:
8658     * Displays the credit card registration confirmation page using paypal.
8659     * 
8660     * @apiSuccessExample Success Response Mobile:
8661     * Displays the credit card registration confirmation page using paypal sp version for mobile.
8662     * 
8663     * @apiErrorExample Error Response:
8664     * Redirects to {{ENV}}/
8665     * 
8666     * @apiSampleRequest off
8667     */
8668    public function paypal_payment_credit_register_confirm() {
8669        $this->checkUser(Configure::read('payment_credit_authentication'));
8670
8671        $data = $this->Session->read('paypalPaymentCreditRegisterData');
8672        if (!$data) {
8673            $this->log(__METHOD__ . ' Missing paypal payment credit register data. --> ' . json_encode($data) . ' | user id  --> ' . json_encode($this->sharedUserData['User']['id']), 'card_reregister');
8674            return $this->redirect(myTools::getUrl());
8675        }
8676
8677        // set payment gateway type
8678        $this->memcache->set(array(
8679            'key' => 'creditReregisterPaymentGatewayType_' . $this->sharedUserData['User']['api_token'],
8680            'value' => $data['payment_gateway_type'],
8681            'expire' => 3600 // 1 hour
8682        ));
8683
8684        $this->set('userApiToken', $this->sharedUserData['User']['api_token']);
8685        $this->set('isSPView', true);
8686        $this->set('paypalFlg', true); // use for modal loader
8687        $renderParam = array(
8688            'forceMobile' => true,
8689            'this' => $this,
8690            'spView' => '/Mobile/Payment/paypal_payment_credit_register_confirm',
8691            'layout' => 'mobile'
8692        );
8693
8694        myTools::render($renderParam);
8695    }
8696    /**
8697     * @api {get} /:language/payment/paypal_payment_credit_register_process/:token/:negativeTesting paypal_payment_credit_register_process()
8698     * @apiName paypal_payment_credit_register_process
8699     * @apiGroup Payment
8700     * @apiDescription This function is used to process the credit card registration using paypal.
8701     * 
8702     * @apiParam {String} language Language code of the user
8703     * @apiParam {String} token User's API token
8704     * @apiParam {Number} negativeTesting Negative testing flag 1 for true, 0 for false
8705     * 
8706     * @apiSuccess {View} Redirect Redirects to {{ENV}}/:language/payment/payment_credit_register_compelete page if successful.
8707     * 
8708     * @apiError {View} Redirect Redirects to {{ENV}}/ page if token is not set or does not match the user's API token.
8709     * @apiError {View} Redirect Redirects to {{ENV}}/payment/payment_credit_register page if negative testing is enabled
8710     * @apiError {View} Redirect Redirects to {{ENV}}/ page if session payment credit register data is missing.
8711     * @apiError {View} Redirect Redirects to {{ENV}}/payment/payment_credit_register page if settlement fails.
8712     * 
8713     * @apiSuccessExample Success Response:
8714     * Redirects to {{ENV}}/:language/payment/payment_credit_register_compelete
8715     * 
8716     * @apiErrorExample Error Response token not set:
8717     * Redirects to {{ENV}}/
8718     * 
8719     * @apiErrorExample Error Response Negative Testing:
8720     * Redirects to {{ENV}}/payment/payment_credit_register
8721     * 
8722     * @apiErrorExample Error Response Missing Data:
8723     * Redirects to {{ENV}}/
8724     * 
8725     * @apiErrorExample Error Response Settlement Fails:
8726     * Redirects to {{ENV}}/payment/payment_credit_register
8727     * 
8728     * @apiSampleRequest off
8729     */
8730    public function paypal_payment_credit_register_process() {
8731        $this->autoRender = false;
8732        $this->layout = false;
8733
8734        $logFileName = 'paypal_debug';
8735        $user = $this->sharedUserData['User'];
8736        $userId = $user['id'];
8737        $get = $this->request->query;
8738
8739        //- NJ-27262 clear from landing page
8740        $this->Cookie->delete('chocotto_lp');
8741
8742        // negative testing
8743        if (isset($get['negativeTesting']) && $get['negativeTesting']) {
8744            $this->Session->setFlash('決済失敗', array("element" => "flashfail"));
8745
8746            $memKey = 'paypalBillingAgreementData_' . $get['token'];
8747
8748            // delete memcache billing agreement data
8749            if ($this->memcache->get($memKey)) {
8750                $this->memcache->delete($memKey);
8751            }
8752
8753            return $this->redirect(myTools::getUrl('payment/payment_credit_register'));
8754        }
8755
8756
8757        // get session payment credit register data
8758        $data = $this->Session->read('paypalPaymentCreditRegisterData');
8759
8760        // redirect to top page if empty
8761        if (!$data) {
8762            $this->log(__METHOD__ . ' Missing paypal payment credit register data. --> ' . json_encode($data) . ' | user id  --> ' . json_encode($userId), $logFileName);
8763            return $this->redirect(myTools::getUrl());
8764        }
8765
8766        // redirect to top page if get token is not set or get token is not same as user api token
8767        if (!isset($get['token']) || (isset($get['token']) && $get['token'] != $user['api_token'])) {
8768            $this->log(__METHOD__ . ' Token does not exist. --> ' . json_encode($get) . ' | user data  --> ' . json_encode($user), $logFileName);
8769            return $this->redirect(myTools::getUrl());
8770        }
8771
8772        $data['formType'] = Configure::read('payment_credit_authentication');
8773
8774        $userTable = new UserTable($user);
8775        $membershipTypes = UserTable::getEngMembershipTypeData();
8776        $membershipTypeIndex = $userTable->getMembershipTypeIndex();
8777
8778        $paymentPlanType = (isset($get['payment_plan_type']) && $get['payment_plan_type'] ) ? $get['payment_plan_type'] : 0;
8779
8780        $user['statusBefore'] = $membershipTypes[$membershipTypeIndex];
8781        $user['statusAfter'] = $membershipTypes[2];
8782
8783        // update if select lite plan
8784        if ($paymentPlanType == Configure::read('register_plan_types.light')) {
8785            // - fetch the lite payment plan 
8786            $litefreeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
8787                'currencyCode' => $user['currency_code'],
8788                'paymentPlanId' => Configure::read('payment_plans.light_plan_free'),
8789                'logFileName' => 'card_reregister'
8790            ));
8791
8792            $_lightPlanFreeMem = Configure::read('membership_type_lightplan_free');
8793            $user['statusAfter'] = $membershipTypes[$_lightPlanFreeMem];// update the status after to lite plan free
8794
8795            // - set update data 
8796            $data['paymentPlanData'] = $litefreeTrialData;// set to update the plan use
8797
8798            // update the form type 
8799            $data['formType'] = myTools::getLitePlanUserFormType(Configure::read('payment_plans.light_plan_free'));
8800
8801        // if annual discount option
8802        } elseif ($paymentPlanType == Configure::read('register_plan_types.premium_with_annual_discount_option')) {
8803            $annualDiscountOptionData = $this->DiscountOptionsPrice->getPaymentData(['currencyCode' => $userTable->currency_code, 'discountOptionId' => Configure::read('discount_option.annual.plan_id')]);
8804    
8805            // redirect to credit page if annual discount option does not exist or is not enabled
8806            if (!$annualDiscountOptionData) {
8807                $this->log(__METHOD__ . ' Annual discount pption does not exist. --> ' . json_encode($get) . ' | data  --> ' . json_encode($data), $logFileName);
8808                return $this->redirect(myTools::getUrl());
8809            }
8810
8811            $annualDiscountOptionData['amount'] = 0; // change amount to 0 since this is a subscription
8812            $annualDiscountOptionData += [
8813                'dosh_event' => Configure::read('discount_option.dosh_event.annual_discount'),
8814                'dosh_status' => Configure::read('discount_option.dosh_status.subscription')
8815            ];
8816
8817            $data['discountOption'] = $annualDiscountOptionData;
8818
8819        //- chocotto payment plan
8820        } elseif ($paymentPlanType == Configure::read('register_plan_types.chocotto')) {
8821            // - fetch the chocotto payment plan 
8822            $chocottofreeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
8823                'currencyCode' => $user['currency_code'],
8824                'paymentPlanId' => Configure::read('payment_plans.free_trial_chocotto'),
8825                'logFileName' => 'card_register'
8826            ));
8827
8828            $this->UsersDetail->chocottoCampUserDetails($user['id']);
8829            $_chocottoPlanFreeMem = Configure::read('membership_type_chocotto_plan_free');
8830            $user['statusAfter'] = $membershipTypes[$_chocottoPlanFreeMem];// update the status after to lite plan free
8831
8832            // - set update data 
8833            $data['paymentPlanData'] = $chocottofreeTrialData;// set to update the plan use
8834
8835            // update the form type 
8836            $data['formType'] = myTools::getChocottoPlanUserFormType(Configure::read('payment_plans.free_trial_chocotto'));
8837
8838        }
8839
8840        // process paypal settlement
8841        $result = $this->paypalSaveBillingAgreement($data, $user);
8842
8843        // delete session payment credit register data
8844        $this->Session->delete('paypalPaymentCreditRegisterData');
8845
8846        // redirect to reregister page if result is false
8847        if (!$result['success']) {
8848            $this->Session->setFlash('決済失敗', array("element" => "flashfail"));
8849
8850            $memKey = 'paypalBillingAgreementData_' . $get['token'];
8851
8852            // delete memcache billing agreement data
8853            if ($this->memcache->get($memKey)) {
8854                $this->memcache->delete($memKey);
8855            }
8856
8857            $result['status'] = 0;
8858
8859            // update payment transaction
8860            $this->PaymentTransaction->paypalUpdatePaymentTransaction($result);
8861
8862            return $this->redirect(myTools::getUrl('payment/payment_credit_register'));
8863        }
8864
8865        $reCampaign = $this->UserWithdrawReenrollCampaign->find('first', array(
8866            'fields' => array('id', 'status'),
8867            'conditions' => array('user_id' => $userId)
8868        ));
8869
8870        if (
8871            isset($reCampaign['UserWithdrawReenrollCampaign']['status']) &&
8872            $reCampaign['UserWithdrawReenrollCampaign']['status'] == 0 &&
8873            $user['currency_code'] == Configure::read('currency_jpy') &&
8874            $paymentPlanType != Configure::read('register_plan_types.chocotto') //- no service coin for chocotto plan
8875        ) {
8876            $uwrcId = $reCampaign['UserWithdrawReenrollCampaign']['id'];
8877
8878            // give 500 points
8879            $pointParams = array(
8880                'userId' => $userId,
8881                'point' => 500, // re-register campaign points
8882                'kbn' => Configure::read("point_history.bonus"),
8883                'kbnType' => 1, // add coin
8884                'coinType' => 2, // service coin
8885                'coinFailMessage' => Configure::read('coin.failed.buy_coin')
8886            );
8887
8888            ClassRegistry::init('UsersPoint')->performPointTransaction($pointParams);
8889
8890            // update re-enroll campaign status
8891            $rcData = array('id' => $uwrcId, 'status' => 1);
8892
8893            $this->UserWithdrawReenrollCampaign->clear();
8894            $this->UserWithdrawReenrollCampaign->read(array_keys($rcData), $uwrcId);
8895            $this->UserWithdrawReenrollCampaign->set($rcData);
8896            $this->UserWithdrawReenrollCampaign->save();
8897        }
8898
8899        // send registration completion email
8900        App::uses('myMailer','Lib');
8901        $mailId = Configure::read('site_in_mail.student_registration_complete');
8902        myMailer::sendTemplateMail($mailId, $user['email'], $user, array(), 'User');
8903
8904        $memKey = 'creditReregisterPaymentGatewayType_' . $user['api_token'];
8905        // delete memcache payment gateway type
8906        if ($this->memcache->get($memKey)) {
8907            $this->memcache->delete($memKey);
8908        }
8909        // NJ-13482
8910        $this->Session->write('payment_credit_register_complete', true);
8911
8912        return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_register_complete'));
8913    }
8914
8915    /**
8916     * @api {get} /payment/sp_paypal_payment_credit_register_process/:token/:negativeTesting/:payment_plan_type sp_paypal_payment_credit_register_process()
8917     * @apiName sp_paypal_payment_credit_register_process
8918     * @apiGroup Payment
8919     * @apiDescription This endpoint is used to process the credit card registration using paypal for sp mobile.
8920     * 
8921     * @apiParam {String} token User's API token
8922     * @apiParam {Number} negativeTesting Negative testing flag 1 for true, 0 for false
8923     * @apiParam {Number} payment_plan_type Payment plan type
8924     * 
8925     * @apiSuccess {View} Redirect Redirects to {{ENV}}/payment/paypal_payment_credit_register_process page if successful.
8926     * 
8927     * @apiError {View} Redirect Redirects to {{ENV}}/ page if token is not set or does not match the user's API token.
8928     *
8929     * @apiSuccessExample Success Response:
8930     * Redirects to {{ENV}}/payment/paypal_payment_credit_register_process
8931     * 
8932     * @apiErrorExample Error Response:
8933     * Redirects to {{ENV}}/
8934     * 
8935     * @apiSampleRequest off
8936     */
8937    public function sp_paypal_payment_credit_register_process() {
8938        $this->autoLayout = false;
8939        $this->autoRender = false;
8940
8941        $this->checkUser(Configure::read('payment_credit_authentication'));
8942
8943
8944        $params = array();
8945        $get = $this->request->query;
8946        $user = $this->sharedUserData['User'];
8947        $logFileName = 'card_reregister';
8948
8949        $paymentPlanType = (isset($get['payment_plan_type'])) ? $get['payment_plan_type'] : null;
8950
8951        $freeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
8952            'currencyCode' => $user['currency_code'],
8953            'paymentPlanId' => Configure::read('payment_plans.free_trial'),
8954            'logFileName' => $logFileName
8955        ));
8956
8957        if ((int) $paymentPlanType == 1) {
8958            $freeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
8959                'currencyCode' => $user['currency_code'],
8960                'paymentPlanId' => Configure::read('payment_plans.light_plan_free'),
8961                'logFileName' => $logFileName
8962            ));
8963
8964        //- NJ-27262 new chocotto plan
8965        } elseif ($paymentPlanType == Configure::read('register_plan_types.chocotto')) {
8966            $freeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
8967                'currencyCode' => $user['currency_code'],
8968                'paymentPlanId' => Configure::read('payment_plans.free_trial_chocotto'),
8969                'logFileName' => $logFileName
8970            ));
8971        }
8972
8973        if (!$freeTrialData) {
8974            return $this->redirect('/');
8975        }
8976        if (isset($get['token']) && $get['token']) {
8977            $params['token'] = $get['token'];
8978        }
8979        
8980        if (isset($get['negativeTesting']) && $get['negativeTesting']) {
8981            $params['token'] = $get['negativeTesting'];
8982        }
8983        
8984
8985
8986        $data['paymentPlanData'] = $freeTrialData;
8987        $this->Session->write('paypalPaymentCreditRegisterData', $data);
8988        return $this->redirect(array('controller' => 'Payment', 'action' => 'paypal_payment_credit_register_process', '?' => $params));
8989    }
8990
8991    /**
8992     * @api {get} /:language/payment/wp_credit_register_form wp_credit_register_form()
8993     * @apiName wp_credit_register_form
8994     * @apiGroup Payment
8995     * @apiDescription This endpoint is used to display the credit card registration form.
8996     * 
8997     * @apiParam {String} language Language code of the user
8998     *
8999     * @apiSuccess {View} Render Displays the credit card registration form.
9000     * 
9001     * @apiError {View} Redirect Redirects to {{ENV}}/ page if memcache card type is not set.
9002     *  
9003     * @apiSuccessExample Success Response:
9004     * Display the credit card registration form.
9005     * 
9006     * @apiErrorExample Error Response:
9007     * Redirects to {{ENV}}/
9008     * 
9009     * @apiSampleRequest off
9010     */
9011    public function wp_credit_register_form() {
9012        $this->blockWithdrawnSapuriToS();
9013        $this->disablePageForSapuri();
9014        $this->response->disableCache();
9015        $formType = Configure::read('payment_credit_authentication');
9016        $this->checkUser($formType);
9017        $apiToken = $this->sharedUserData['User']['api_token'];
9018
9019        $memKey = "pc_wp_register_card_type_{$apiToken}";
9020        // redirect to mypage if memcache card type is not set
9021        if (!$this->memcache->get($memKey)) {
9022            return $this->redirect('/');
9023        }
9024
9025        //NJ-3882 Require SMS Authentication before Credit Card Registration
9026        $this->PhoneVerifyCheckLog->openDBReplica();
9027        $countTotalVerify = $this->PhoneVerifyCheckLog->find('count',array(
9028            'conditions'=> array(
9029                'user_id' => $this->Auth->user('id'),
9030                'status' => 0
9031            )
9032        ));
9033        $this->PhoneVerifyCheckLog->closeDBReplica();
9034        
9035        $this->CountryCode->openDBReplica();
9036        $countryCodes = $this->CountryCode->find('all',array(
9037            'fields' => array(
9038                'code',
9039                'country_name'
9040            ),
9041            'order' => 'country_name ASC'
9042        ));
9043        $this->CountryCode->closeDBReplica();
9044        $this->set('countryCodes',$countryCodes);
9045        
9046        $user = new UserTable($this->sharedUserData['User']);
9047        $this->set('user', $user);
9048        $this->set('countTotalVerify',$countTotalVerify);
9049
9050        // set view vars
9051        $this->set('pmtValue', 'auth');
9052        $this->set('apiToken', $apiToken);
9053        $this->set('logFileName', 'card_reregister');
9054        $this->set('nc_terminal_type', 1); // pc
9055        $this->set('memKeyError', 'pc_wp_register_error_' . $apiToken);
9056        $this->set('formType', $formType);
9057        $this->set('referrer', urlencode(myTools::getUrl() . "/{$this->localizeDir}/payment/payment_credit_register"));
9058        $this->set('successUrl', urlencode(myTools::getUrl() . "/{$this->localizeDir}/payment/payment_credit_register_complete"));
9059
9060        $renderParam = array(
9061            'forceMobile' => true,
9062            'this' => $this,
9063            'spView' => '/Mobile/Payment/wp_payment_credit_register_form',
9064            'layout' => 'mobile'
9065        );
9066
9067        myTools::render($renderParam);
9068    }
9069
9070    /**
9071     * @api {get} /:language/payment/payment_credit_change payment_credit_change()
9072     * @apiName payment_credit_change
9073     * @apiGroup Payment
9074     * @apiDescription This endpoint is used to display the credit card information change page.
9075     * 
9076     * @apiParam {String} language Language code of the user
9077     * 
9078     * @apiSuccess {View} Render Displays the credit card information change page.
9079     * 
9080     * @apiSuccessExample Success Response:
9081     * Display the credit card information change page.
9082     * 
9083     * @apiSampleRequest off
9084     */
9085    public function payment_credit_change() {
9086        $this->blockWithdrawnSapuriToS();
9087        $this->disablePageForSapuri();
9088        $this->set('title_for_layout', 'クレジットカード情報変更|オンライン英会話のネイティブキャンプ');
9089        $userData = $this->sharedUserData['User'];
9090        $userObj = new UserTable($userData);
9091
9092        // NJ-68818: check if payment was charged after challenge already
9093        $this->checkIfChargedAfterChallenge($userData['id'], 'payment_change');
9094
9095        if(
9096            (
9097                in_array($userObj->getMembershipTypeIndex(), array(12,13)) && 
9098                !empty($userData['corporate_id'])
9099            ) || 
9100            in_array($userObj->getMembershipTypeIndex(), Configure::read('common_corporate_payment_memberships'))
9101        ) {
9102            return $this->redirect(myTools::getUrl() . '/common_corporate_payment?type=' . Configure::read('payment_url_type.corporate_type.corporate_change_payment_credit') . '&from_page=account');
9103        }
9104        // redirect to zeus if currency is equals to jpy
9105        if ($this->sharedUserData['User']['currency_code'] == Configure::read('default.user_currency')) {
9106            $this->zeus_credit_change();
9107        // redirect to wp
9108        } else {
9109            $this->wp_credit_change();
9110        }
9111
9112        // NJ-30828: set view to display user's paypal email
9113        $this->setPaypalUser($userData);
9114    }
9115
9116    public function zeus_credit_change() {
9117        $user = $this->sharedUserData['User'];
9118        $targetUrl = $url = "";
9119
9120        // app plan user
9121        if ($user['card_company'] == Configure::read('card_company.apple') || $user['card_company'] == Configure::read('card_company.google')) {
9122            $message = "アプリよりご登録の方はカード変更ができません。";
9123            $this->Session->setFlash($message, '', array(), 'plan_list');
9124            return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/plan/plan_list");
9125        }
9126
9127        // free user and not corporate individual user
9128        if (
9129            ($user['charge_flg'] == 0 || $user['fail_flg'] == 1) &&
9130            !in_array($user['payment_plan_id'], myTools::getIndividualPaymentPlanIds())
9131        ) {
9132            $message = "無料会員の方はカード変更ができません。";
9133            $this->Session->setFlash($message, '', array(), 'plan_list');
9134            return $this->redirect(myTools::getUrl() . '/plan/plan_list', 301);
9135        }
9136
9137        // get request data
9138        $requestData = $this->request->query;
9139
9140        $telecomDisabled = false;
9141        $formType = Configure::read('payment_credit_change');
9142
9143        // check if disabled is set
9144        if (!isset($requestData["disabled"])) {
9145            # check if allowed
9146            $this->checkUser($formType);
9147        } else {
9148            $telecomDisabled = true;
9149        }
9150
9151        // check if there's a post data
9152        if ($this->request->is('post')) {
9153            $data = $this->request->data;
9154            
9155            // - set zeuspay logs
9156            $data['ZPaymentFullLogs']['clientip'] = Configure::read('ZEUS_clientip');
9157            $data['ZPaymentFullLogs']['telno'] = Configure::read('credit.default_telno');
9158            
9159            // check if token matches token in session
9160            $checkToken = $this->checkToken($data['token']);
9161
9162            // check if token is true
9163            if ($checkToken) {
9164                $this->unsetToken();
9165
9166                if ( isset($requestData['page_origin']) ) {
9167                    if ( isset($requestData['page_origin']) && $requestData['page_origin'] == 1 ) { // Store
9168                        $url = "page_origin=".$requestData['page_origin'];
9169                    } elseif (isset($requestData['page_origin']) && $requestData['page_origin'] == 2) { // Ebook
9170                        $url = "page_origin=".$requestData['page_origin'];
9171                    }
9172                    $data['origin_redirect'] = $url;
9173                }
9174                $referrer =  array('controller' => 'Payment', 'action' => 'payment_credit_change');
9175                $this->z_start($data, $formType, $referrer);
9176            }
9177        }
9178
9179        $user = $this->changePaymentPlanIfTelecomUser($user);
9180        // set payment amount
9181        $user['paymentAmount'] = 0;
9182
9183        // if corporate user
9184        if (isset($user['corporate_id']) && $user['corporate_id']) {
9185            $user['corporateSettlementType'] = Configure::read('corporate_settlement_types.change_card');
9186        }
9187
9188        // - NJ-18780 check if lite plan user 
9189        $isLitePlanUser = in_array($user['payment_plan_id'], Configure::read('lite_payment_plans')) ? true : false;
9190
9191        // set transaction error to 1 if failed to create payment transaction
9192        if (!$pt = $this->createPaymentTransaction(Configure::read('payment_credit_change'), $user)) {
9193            $this->set('transactionError', 1);
9194        }
9195
9196        // NJ-23812 : set view for corporate payment 
9197        $corporateIndiUser = false;
9198        $corporateUser = !empty($user['corporate_id']) && $user['corporate_id'] && isset($user['payment_plan_id']) ? true : false;
9199        $cpData = null;
9200        $cAmount = $cfAmount = "";
9201        $isCardRegistered = (!empty($user['card_brand']) && !empty($user['card_number'])) ? true : false;
9202
9203        $isZeusUser = isset($user['card_company']) && $user['card_company'] == 1 ? true : false;
9204
9205        //NJ-23812: if corporate user
9206        if ($corporateUser) {
9207            // get corporate plan data
9208            $cpData = $this->getCorporatePaymentPlan($user);
9209
9210            // return to top page if not supported
9211            if (!$cpData) {
9212                return $this->redirect(myTools::getUrl() . '/');
9213            }
9214
9215            $cfAmount = $cpData['fAmount'];
9216            $corporateIndiUser = $cpData['corporateIndiUser'];
9217        }
9218        
9219        //NJ-23812: - if corp indie user
9220        if ($corporateIndiUser) {
9221            $corporateTaxRate = Configure::read('tax.increase');
9222            $corpType = myTools::getCoporateTypeUsingPaymentPlanId($user['payment_plan_id']);
9223            // light
9224            if ($corpType == Configure::read('corporate_type.light')) {
9225                $indiCorpTypeLight = true;
9226                $getCorporateData = $this->Corporate->getCorporateLightUserMonthly(array('user_id' => $userId, 'remove_heavy_flg' => true));
9227                $basicFeeWoTax = isset($getCorporateData['basic_fee_discounted']) ? $getCorporateData['basic_fee_discounted'] : 0;
9228        
9229                $cfAmount = myTools::formatAmount($basicFeeWoTax);
9230
9231            // standard or premium
9232            }elseif (in_array($corpType, array(Configure::read('corporate_type.premium'), Configure::read('corporate_type.standard')))) {
9233                $cdrParam = array('corporateId' => $user['corporate_id'], 'corporateType' => $corpType);
9234                $discount = (int)$this->CorporateDiscountRate->getDiscount($cdrParam);
9235                $cAmount = (int)$cpData['amount'] - $discount;
9236                $cfAmount = myTools::formatAmount($cAmount);
9237            }
9238        }
9239
9240        $corpType = myTools::getCoporateTypeUsingPaymentPlanId($user['payment_plan_id']);
9241        // NJ-23812 - set corp user indie
9242        $this->set('corporateIndiUser',$corporateIndiUser);
9243        $this->set('corporateType',$corpType);
9244        $this->set('cpFormatAmount', $cfAmount);
9245        $this->set('cpAmount', $cAmount);
9246        $this->set('isZeusUser', $isZeusUser);
9247
9248        $this->set('cardBrand', $user['card_brand']);
9249        $this->set('cardNumber', $user['card_number']);
9250        $this->set('cardLogo', myTools::getWorldpayCardLogo($user['card_brand']));
9251        
9252        // clear previously set tokens and set new token
9253        $this->unsetToken();
9254        $token = md5(uniqid(rand(), true));
9255        $this->Session->write('Payment.token', $token);
9256
9257        if ( isset($requestData['page_origin']) && $requestData['page_origin'] == 1 ) { // Store
9258            $targetUrl = "?page_origin=1";
9259        } elseif (isset($requestData['page_origin']) && $requestData['page_origin'] == 2) { // Ebook
9260            $targetUrl = "?page_origin=2";
9261        }
9262
9263        // set vars
9264        $this->setSupportPayPal($user);
9265        $this->set('targetUrl', $targetUrl);
9266        $this->set('token', $token);
9267        $this->set("telecomDisabled", $telecomDisabled);
9268        $this->set('zeusTransactionFlag', true);
9269        $this->set('paymentHash', $pt['payment_hash']);
9270        $this->set('userApiToken', $user['api_token']);
9271        $this->setPaymentViewVars();
9272    }
9273    /**
9274     * @api {get} /payment/paypal_payment_credit_change_process/:token paypal_payment_credit_change_process()
9275     * @apiName paypal_payment_credit_change_process
9276     * @apiGroup Payment
9277     * @apiDescription This endpoint is used to process the credit card information change using paypal.
9278     * 
9279     * @apiParam {String} token User's API token
9280     * 
9281     * @apiSuccess {View} Redirect Redirects to {{ENV}}/payment/payment_credit_change_complete page if successful.
9282     * 
9283     * @apiError {View} Redirect Redirects to {{ENV}}/ page if token is not set or does not match the user's API token.
9284     * @apiError {View} Redirect Redirects to {{ENV}}/payment/payment_credit_change page if settlement fails.
9285     * 
9286     * @apiSuccessExample Success Response:
9287     * Redirects to {{ENV}}/payment/payment_credit_change_complete
9288     * 
9289     * @apiErrorExample Error Response token not set:
9290     * Redirects to {{ENV}}/
9291     * 
9292     * @apiErrorExample Error Response Settlement Fails:
9293     * Redirects to {{ENV}}/payment/payment_credit_change
9294     * 
9295     * @apiSampleRequest off
9296     */
9297    public function paypal_payment_credit_change_process() {
9298        $this->autoRender = false;
9299        $this->layout = false;
9300
9301        $logFileName = 'paypal_debug';
9302        $user = $this->sharedUserData['User'];
9303        $userId = $user['id'];
9304        $get = $this->request->query;
9305
9306        // redirect to top page if get token is not set or get token is not same as user api token
9307        if (!isset($get['token']) || (isset($get['token']) && $get['token'] != $user['api_token'])) {
9308            $this->log(__METHOD__ . ' Token does not exist. --> ' . json_encode($get) . ' | user data  --> ' . json_encode($user), $logFileName);
9309            return $this->redirect(myTools::getUrl());
9310        }
9311
9312        $data = array(
9313            'paymentPlanData' => array(
9314                'paymentPlanId' => $user['payment_plan_id'],
9315                'priceId' => $user['price_id']
9316            ),
9317            'formType' => Configure::read('payment_credit_change')
9318        );
9319
9320        // process paypal settlement
9321        $result = $this->paypalSaveBillingAgreement($data, $user);
9322
9323
9324        // redirect to reregister page if result is false
9325        if (!$result['success']) {
9326            $this->Session->setFlash('決済失敗', array("element" => "flashfail"));
9327
9328            $memKey = 'paypalBillingAgreementData_' . $get['token'];
9329
9330            // delete memcache billing agreement data
9331            if ($this->memcache->get($memKey)) {
9332                $this->memcache->delete($memKey);
9333            }
9334
9335            $result['status'] = 0;
9336
9337            // update payment transaction
9338            $this->PaymentTransaction->paypalUpdatePaymentTransaction($result);
9339
9340            return $this->redirect(myTools::getUrl('payment/payment_credit_change'));
9341        }
9342
9343        // redirect to payment change complete
9344        return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_change_complete'));
9345    }
9346
9347    public function wp_credit_change() {
9348
9349        // - NJ-23812
9350        if ($this->Session->read('credit_skip_to_confirmation')) {
9351            $this->Session->delete('credit_skip_to_confirmation');
9352        }
9353
9354        $this->checkUser(Configure::read('payment_credit_change'));
9355        $apiToken = $this->sharedUserData['User']['api_token'];
9356        
9357        /* check if there is error during payment process */
9358        if ($errorType = isset($this->request->query['wpErrType']) ? $this->request->query['wpErrType'] : null) {
9359            if ($error = myTools::getWorldpayErrorMsg($errorType)) {
9360                $this->set('error', $error);
9361            }
9362        } else {
9363            $memErrorKey = 'pc_wp_change_error_'.$apiToken;
9364            if ($error = $this->memcache->get($memErrorKey)) {
9365                $this->set('error', $error);
9366
9367                // delete memcache error
9368                $this->memcache->delete($memErrorKey);
9369            }
9370        }
9371        
9372        // memcache credit change
9373        $this->memcache->set(array(
9374            'key' => "pc_wp_change_{$apiToken}",
9375            'value' => array('change' => true),
9376            'expire' => 3600 // 1 hr
9377        ));
9378        
9379        $redirectUrl = myTools::getUrl(). "/{$this->localizeDir}" . '/payment/wp_credit_change_form';
9380        return $this->redirect($redirectUrl); 
9381
9382        $this->render('/payment/wp_payment_credit_change');
9383    }
9384    /**
9385     * @api {get}/:language/payment/wp_credit_change_form wp_credit_change_form()
9386     * @apiName wp_credit_change_form
9387     * @apiGroup Payment
9388     * @apiDescription This endpoint is used to display the credit card information change page.
9389     * 
9390     * @apiParam {String} language Language code of the user
9391     * 
9392     * @apiSuccess {View} Render Displays the credit card information change page.
9393     * 
9394     * @apiError {View} Redirect Redirects to {{ENV}}/ if memcache credit change is not set.
9395     * 
9396     * @apiSuccessExample Success Response:
9397     * Display the credit card information change page.
9398     * 
9399     * @apiErrorExample Error Response:
9400     * Redirects to {{ENV}}/ if memcache credit change is not set.
9401     * 
9402     * @apiSampleRequest off
9403     */
9404    public function wp_credit_change_form() {
9405
9406        $this->blockWithdrawnSapuriToS();
9407        $this->disablePageForSapuri();
9408        $this->response->disableCache();
9409        $formType = Configure::read('payment_credit_change');
9410        $this->checkUser($formType);
9411        $apiToken = $this->sharedUserData['User']['api_token'];
9412        $user = $this->sharedUserData['User'];
9413        
9414        $memKey = "pc_wp_change_{$apiToken}";
9415        // redirect to mypage if memcache credit change is not set
9416
9417        if (!$this->memcache->get($memKey)) {
9418            return $this->redirect('/');
9419        }
9420
9421        $isCardRegistered = (!empty($user['card_brand']) && !empty($user['card_number'])) ? true : false;
9422
9423        $this->set('isCardRegistered', $isCardRegistered);
9424        $this->set('cardNumber', $user['card_number']);
9425        $this->set('cardBrand', $user['card_brand']);
9426        $this->set('cardLogo', myTools::getWorldpayCardLogo($user['card_brand']));
9427
9428        // set view vars
9429        $this->set('pmtValue', 'auth');
9430        $this->set('apiToken', $apiToken);
9431        $this->set('logFileName', 'card_change');
9432        $this->set('nc_terminal_type', 1); // pc
9433        $this->set('memKeyError', 'pc_wp_change_error_' . $apiToken);
9434        $this->set('referrer', urlencode(myTools::getUrl(). "/{$this->localizeDir}/payment/payment_credit_change"));
9435        $this->set('successUrl', urlencode(myTools::getUrl()."/{$this->localizeDir}/payment/payment_credit_change_complete"));
9436        $this->set('formType', Configure::read('payment_credit_change'));
9437    }
9438
9439    /**
9440     * @api {post} /:language/payment/payment_credit_charge/:cc payment_credit_charge()
9441     * @apiName payment_credit_charge
9442     * @apiGroup Payment
9443     * @apiDescription This endpoint is used to display the credit card charge page.
9444     * 
9445     * @apiParam {String} language Language code of the user
9446     * @apiParam {String} cc Campaign code/ Blank if no campaign code
9447     * 
9448     * @apiSuccess {View} Render Displays the credit card charge page.
9449     * @apiSuccess {View} Redirect Redirect to zeus credit charge function if currency is equals to jpy.
9450     * @apiSuccess {View} Redirect Redirect to wp credit charge function if currency is not equals to jpy.
9451     * 
9452     * @apiSuccessExample Success Response:
9453     * Display the credit card charge page.
9454     * 
9455     * @apiSuccessExample Success Response jpy currency:
9456     * Redirect to zeus credit charge function.
9457     * 
9458     * @apiSuccessExample Success Response not jpy currency:
9459     * Redirect to wp credit charge function.
9460     * 
9461     * @apiSampleRequest off
9462     */
9463    public function payment_credit_charge() {
9464        $this->blockWithdrawnSapuriToS();
9465        $this->disablePageForSapuri();
9466        $this->checkUser(Configure::read('payment_credit_force_charge'));
9467        $this->set('monthlyPriceSymbol', myTools::getCurrencySymbol($this->sharedUserData['User']['currency_code']));
9468        $userData = $this->sharedUserData['User'];
9469        $userObj = new UserTable($userData);
9470
9471        // NJ-68818: check if payment was charged after challenge already
9472        $this->checkIfChargedAfterChallenge($userData['id'], 'rejoin');
9473        
9474        // NC-8697: delete from deactivated user list
9475        $memCached = new myMemcached();
9476        $memCached->delete('deactivated-user-'.$this->sharedUserData['User']['id']);
9477        UserTable::deleteUserDeactivationLock($this->sharedUserData['User']['id']);
9478        
9479        // NC-7644
9480        $get_params = $this->params->query;
9481        $campaign_code = isset($get_params['cc']) ? $get_params['cc'] : '';
9482        $get_params = (!empty($campaign_code)) ? '?cc='.$campaign_code : '';
9483        $this->set('get_campain_params', $get_params);
9484        if ($campaign_code) {
9485            /* NC-7644 insert to memCached unique mem id */ 
9486            $memCached->set(array(
9487                'key' => 'campaign_code_CC_RE10' . $this->Auth->user('id'),
9488                'value' => true
9489            ));
9490        }else {
9491            if (!$this->request->is('post')) {
9492                // get the campaign `CC_RE10` unique memCached
9493                $memKey = 'campaign_code_CC_RE10' . $this->Auth->user('id');
9494                $memCached->delete($memKey);
9495            }
9496        }
9497
9498        $this->setPerMonthSymbol($this->localizeDir, true);
9499
9500        // NJ-32737
9501        $this->setCouponUseData($this->sharedUserData['User']['id'], $this->sharedUserData['User']['currency_code']);
9502
9503        // redirect to zeus if currency is equals to jpy
9504        if ($this->sharedUserData['User']['currency_code'] == Configure::read('default.user_currency')) {
9505            $this->zeus_credit_charge();
9506        // redirect to wp
9507        } else {
9508            $this->wp_credit_charge();
9509        }
9510
9511        // NJ-30828: set view to display user's paypal email
9512        $this->setPaypalUser($userData);
9513    }
9514
9515    private function zeus_credit_charge() {
9516        $formType = Configure::read('payment_credit_force_charge');
9517        $user = $this->sharedUserData['User'];
9518        $currencyCode = $user['currency_code'];
9519        $logFileName = 'card_charge';
9520
9521        // get premium payment plan data
9522        $ppData = $this->PaymentPlanPrice->getPaymentData(array(
9523            'currencyCode' => $currencyCode,
9524            'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
9525            'logFileName' => $logFileName
9526        ));
9527
9528        #chocotto plan data
9529        $chocottoPlanData = $this->PaymentPlanPrice->getPaymentData(array(
9530            'currencyCode' => $user['currency_code'],
9531            'paymentPlanId' => Configure::read('payment_plans.chocotto_plan'),
9532            'logFileName' => $logFileName ?? 'card_reregister'
9533        ));
9534
9535        // - set chocotto plan price
9536        $this->set('chocottoMonthlyPrice',$chocottoPlanData['fAmount']);
9537        $this->set('chocottoMonthlyPriceNoTax', myTools::formatAmount($chocottoPlanData['amountConstTaxDeducted']));
9538
9539        // - NJ-23812
9540        if ($this->Session->read('credit_skip_to_confirmation')) {
9541            $this->Session->delete('credit_skip_to_confirmation');
9542        }
9543
9544        if ($this->Session->read('paypalPaymentCreditChargeData')){
9545            $this->Session->delete('paypalPaymentCreditChargeData');
9546        }
9547
9548        // redirect to top page if premium payment plan is not supported
9549        if (!$ppData) {
9550            return $this->redirect(myTools::getUrl() . '/');
9551        }
9552
9553        $corporateIndiUser = false;
9554        $corporateUser = isset($user['corporate_id']) && $user['corporate_id'] ? true : false;
9555        
9556        // get corporate payment method
9557        $this->Corporate->openDBReplica();
9558        $corporateData = $this->Corporate->find('first', array(
9559            'fields' => array('payment_method'),
9560            'conditions' => array('id' => $user['corporate_id']),
9561            'recursive' => -1
9562        ));
9563        $this->Corporate->closeDBReplica();
9564
9565        $corporateData = $corporateData ? $corporateData['Corporate'] : null;
9566
9567        // if corporate is individual payment
9568        if ($corporateUser && $corporateData && $corporateData['payment_method'] == 1) {
9569
9570            // get corporate plan data
9571            $cpData = $this->getCorporatePaymentPlan($user);
9572            // return to top page if not supported
9573            if (!$cpData) {
9574                return $this->redirect(myTools::getUrl() . '/');
9575            }
9576
9577            $cfAmount = $cpData['fAmount'];
9578            $corporateIndiUser = $cpData['corporateIndiUser'];
9579        }
9580
9581        // data needed for corporate individual
9582        if ($corporateIndiUser) {
9583            // NJ-28462
9584            $this->corpIndividualData($user);
9585        }
9586
9587        // NC-3914
9588        $this->getAndSetCardInfo($user);
9589
9590        // NC-4926
9591        $isFamilyPlanBefore = PaymentTable::checkIfFamilyPlan(
9592            $user['id'],
9593            $user['hash16'],
9594            array(
9595                Configure::read('payment_credit_family_free'),
9596                Configure::read('payment_credit_family_monthly_payment')
9597            )
9598        );
9599
9600        $this->set('isFamilyPlanBefore', $isFamilyPlanBefore);
9601        $corpSessionKey = 'PaymentCreditChargeCorporateData';
9602
9603        // get reserve payment receivable
9604        $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($user['id']);
9605
9606        // get live lesson payment receivable
9607        $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($user['id'], false, Configure::read('appreciation_data.payment_element_type'));
9608
9609        // get live lesson payment receivable
9610        $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($user['id'], false, Configure::read('payment_element_type.live'));
9611
9612        $annualDiscountOptionData = $this->DiscountOptionsPrice->getPaymentData(['currencyCode' => $user['currency_code'], 'discountOptionId' => Configure::read('discount_option.annual.plan_id')]);
9613
9614        $corporateTaxRate = Configure::read('tax.increase');
9615
9616        // - check if there is annual discount option data
9617        if ($annualDiscountOptionData) {
9618            unset($annualDiscountOptionData['contract_start']);
9619            $annualDiscountOptionData += [
9620                'dosh_event' => Configure::read('discount_option.dosh_event.annual_discount'),
9621                'dosh_status' => Configure::read('discount_option.dosh_status.monthly_discount')
9622            ];
9623
9624            $annualDiscountOptionAmount = $annualDiscountOptionData['amount'];
9625        }
9626
9627        $monthlyPriceWithAnnualDiscount = $ppData['amount'] - $annualDiscountOptionAmount;
9628        $monthlyPriceWithAnnualDiscountNoTax = $monthlyPriceWithAnnualDiscount / $corporateTaxRate;
9629        $monthlyPriceWithAnnualDiscountNoTax = round($monthlyPriceWithAnnualDiscountNoTax);
9630
9631        $this->set('enableAnnualDiscountOption', $annualDiscountOptionData ? true : false);
9632        $this->set('annualDiscountOptionAmount', myTools::formatAmount($annualDiscountOptionAmount));
9633        $this->set('monthlyPriceWithAnnualDiscount', myTools::formatAmount($monthlyPriceWithAnnualDiscount));
9634        $this->set('monthlyPriceWithAnnualDiscountNoTax', myTools::formatAmount($monthlyPriceWithAnnualDiscountNoTax));
9635
9636        # check if post
9637        if ($this->request->is('post')) {
9638            $data = $this->request->data;
9639
9640            // NJ-32737
9641            $couponData = $this->Session->read('apply_coupon_usage_data');
9642
9643            // redirect to paypal confirm page if payment gateway selected is paypal
9644            if ($data['payment_gateway_type'] == Configure::read('card_company.paypal')) {
9645                $data['paymentPlanData'] = $ppData;
9646                $data['receivablePayment'] = $receivablePayment;
9647                $data['appreciationReceivable'] = $appreciationReceivable;
9648                $data['liveLessonReceivable'] = $liveLessonReceivable;
9649                $data['formType'] = $formType;
9650
9651                if ($annualDiscountOptionData) {
9652                    $user['discountOption'] = $annualDiscountOptionData;
9653                }
9654
9655                // NJ-32737
9656                $membershipStatusIndex = UserTable::getStudentMembershipStatus($user['id']);
9657                if (in_array($membershipStatusIndex, Configure::read('allow_coupon.settlement')) &&
9658                    isset($data['z_payment_form_type']) &&
9659                    in_array($data['z_payment_form_type'], Configure::read('allow_coupon.settlement_form_type'))
9660                ) {
9661                    if (isset($couponData['useCouponAmount']) && $couponData['useCouponAmount'] > 0) {
9662                        if ($data['ZPaymentFullLogs']['money'] >= $couponData['useCouponAmount']) {
9663                            $data['ZPaymentFullLogs']['money'] -= $couponData['useCouponAmount'];
9664                        } else {
9665                            $data['ZPaymentFullLogs']['money'] = 0;
9666                        }
9667
9668                        $data['couponUseSettlement'] = $couponData;
9669                    }
9670                }
9671                // NJ-32737-end
9672
9673                $this->Session->write('paypalPaymentCreditChargeData', $data);
9674                return $this->redirect(myTools::getUrl() . '/payment/paypal_payment_credit_charge_confirm');
9675            }
9676
9677            // delete payment gateway type memcache
9678            $this->memcache->delete('creditChargePaymentGatewayType_' . $user['api_token']);
9679
9680            if( isset($data['ZPaymentFullLogs']['corporatePlan']) ) {
9681                if($data['ZPaymentFullLogs']['corporatePlan'] == 'light') {
9682                    $getPaymentPlanId = $this->getCorporatePaymentPlan($user,array('corporate_type' => 4));
9683                    $getLightCorporateData = $this->Corporate->getCorporateLightUserMonthly(array(
9684                        'user_id' => $user['id'],
9685                        'remove_heavy_flg' => true
9686                    ));
9687                    $paymentLightAmount = isset($getLightCorporateData['total']) ? $getLightCorporateData['total'] : 0;
9688                    $basicLightFee = isset($getLightCorporateData['basic_fee']) ? $getLightCorporateData['basic_fee'] : 0;
9689                    $lessonLightFee = isset($getLightCorporateData['lesson_fee']) ? $getLightCorporateData['lesson_fee'] : 0;
9690                    $basicLightFeeWoTax = isset($getLightCorporateData['basic_fee_discounted']) ? $getLightCorporateData['basic_fee_discounted'] : 0;
9691                    $freeLightNumber = isset($getLightCorporateData['fee_charge_count']) ? $getLightCorporateData['fee_charge_count'] : 0;
9692                    $isLightFreeFlg = isset($getLightCorporateData['free_charge_flg']) ? $getLightCorporateData['free_charge_flg'] : false;
9693                    $monthlyLightFee = isset($getLightCorporateData['monthly_fee_wo_tax']) ? $getLightCorporateData['monthly_fee_wo_tax'] : 0;
9694                    $cfLightAmount = myTools::formatAmount($basicLightFeeWoTax);
9695                    $cLightRawAmount = $basicLightFeeWoTax;
9696                    $lessonLightLimit = $this->Corporate->getLessonLimit($user['corporate_id']);
9697                    $cpData = array(
9698                        'basicFee' => $basicLightFee,
9699                        'lessonFee' => $lessonLightFee,
9700                        'freeFlg' => $isLightFreeFlg,
9701                        'freeNumber' => $freeLightNumber,
9702                        'monthlyFee' => $monthlyLightFee,
9703                        'fAmount' => $cfLightAmount,
9704                        'paymentAmount' => $paymentLightAmount,
9705                        'lessonLimit' => $lessonLightLimit,
9706                        'paymentPlanId' => $getPaymentPlanId['paymentPlanId'],
9707                        'cRawAmount'    => $cLightRawAmount,
9708                        'basicFeeWoTax' => $basicLightFeeWoTax,
9709                        'priceId'        => $getPaymentPlanId['priceId']
9710                    );
9711    
9712                    $data['ZPaymentFullLogs']['indiCorpType'] = 4;
9713                } else if($data['ZPaymentFullLogs']['corporatePlan'] == 'premium') {
9714                    $cpPremuimData = $this->getCorporatePaymentPlan($user,array('corporate_type' => 2));
9715                    
9716                    $cdrPremiumParam = array('corporateId' => $user['corporate_id'], 'corporateType' => 2);
9717                    $discountPremium = (int)$this->CorporateDiscountRate->getDiscount($cdrPremiumParam);
9718                    $cPremiumAmount = (int)$cpPremuimData['amount'] - $discountPremium;
9719                    $cPremiumRawAmount = $cPremiumAmount;
9720                    $cfPremiumAmount = myTools::formatAmount($cPremiumAmount);
9721                    $cpData = array(
9722                        'cprAmount' => $cpPremuimData['amount'],
9723                        'cprDiscount' => $discountPremium,
9724                        'paymentAmount' => $cPremiumAmount * $corporateTaxRate,
9725                        'fAmount' => $cfPremiumAmount,
9726                        'cRawAmount' => $cPremiumRawAmount,
9727                        'ppAmount' => $cpPremuimData,
9728                        'paymentPlanId' => $cpPremuimData['paymentPlanId'],
9729                        'priceId'        => $cpPremuimData['priceId']
9730                    );
9731    
9732                    $data['ZPaymentFullLogs']['indiCorpType'] = 2;
9733                } else {
9734                    $cpStandardData = $this->getCorporatePaymentPlan($user,array('corporate_type' => 1));
9735                    $cdrStandardParam = array('corporateId' => $user['corporate_id'], 'corporateType' => 1);
9736                    $discountStandard = (int)$this->CorporateDiscountRate->getDiscount($cdrStandardParam);
9737                    $cStandardAmount = (int)$cpStandardData['amount'] - $discountStandard;
9738                    $cStandardRawAmount = $cStandardAmount;
9739                    $cfStandardAmount = myTools::formatAmount($cStandardAmount);
9740                    $cpData = array(
9741                        'cprAmount' => $cpStandardData['amount'],
9742                        'cprDiscount' => $discountStandard,
9743                        'paymentAmount' => $cStandardAmount * $corporateTaxRate,
9744                        'fAmount' => $cfStandardAmount,
9745                        'cRawAmount' => $cStandardRawAmount,
9746                        'ppAmount' => $cpStandardData,
9747                        'paymentPlanId' => $cpStandardData['paymentPlanId'],
9748                        'priceId'        => $cpStandardData['priceId']
9749                    );
9750                    $data['ZPaymentFullLogs']['indiCorpType'] = 1;
9751                }
9752                $data['ZPaymentFullLogs']['formType'] = $formType = myTools::getCorporateCompanyCardFormType($cpData['paymentPlanId']);
9753
9754                $corpIndiPrices = $this->Session->read('corporateIndiPrices');
9755                $corpIndiPrices[$data['ZPaymentFullLogs']['corporatePlan']]['plan_type'] = $data['ZPaymentFullLogs']['indiCorpType'];
9756                $this->Session->write($corpSessionKey,$corpIndiPrices[$data['ZPaymentFullLogs']['corporatePlan']]);
9757            }
9758
9759            $data['ZPaymentFullLogs']['clientip'] = Configure::read('ZEUS_clientip');
9760            $data['ZPaymentFullLogs']['telno'] = Configure::read('credit.default_telno');
9761            
9762
9763            if ($this->Session->read('PaymentCreditChargeInfo')) {
9764                $this->Session->delete('PaymentCreditChargeInfo');
9765            }
9766
9767            // - set lite plan flag 
9768            $litePlanFlg = false;
9769
9770            // - set chocotto plan flag 
9771            $chocottoPlanFlg = false;
9772
9773            // - NJ-18780 : check if lite plan type for normal user 
9774            if (
9775                isset($data['ZPaymentFullLogs']['payment_plan_type']) && 
9776                !$corporateIndiUser
9777            ) {
9778                $paymentPlanType = $data['ZPaymentFullLogs']['payment_plan_type'];
9779                $litePlanFlg = ((int) $data['ZPaymentFullLogs']['payment_plan_type']  == 1) ? true : false;
9780                $chocottoPlanFlg = ((int) $data['ZPaymentFullLogs']['payment_plan_type']  == Configure::read('register_plan_types.chocotto'));
9781                if ($litePlanFlg) {
9782                    $_plan_id = Configure::read('payment_plans.light_plan');
9783                    $formType = myTools::getLitePlanUserFormType($_plan_id);
9784                } elseif ($chocottoPlanFlg) {
9785                    $_plan_id = Configure::read('payment_plans.chocotto_plan');
9786                    $formType = Configure::read('payment_credit_chocotto_force_charge');
9787                }else{
9788                    $_plan_id = Configure::read('payment_plans.premium_plan');
9789                    $formType = Configure::read('payment_credit_force_charge');
9790                }
9791
9792                // fetch light plan description
9793                $litePlanData = $this->PaymentPlanPrice->getPaymentData(array(
9794                    'currencyCode' => $currencyCode,
9795                    'paymentPlanId' => $_plan_id,
9796                    'logFileName' => $logFileName
9797                ));
9798
9799                if (!$litePlanData) {
9800                    $this->set('transactionError', 1);
9801                }else{
9802
9803                    // - check if not annual discount option
9804                    if (isset($data['ZPaymentFullLogs']['payment_plan_type']) && $data['ZPaymentFullLogs']['payment_plan_type'] == 0) {
9805                        $annualDiscountOptionAmount = 0;
9806                    }
9807
9808                    // - set light amount 
9809                    $lightPlanAmount = $litePlanData['amount'];
9810
9811                    $data['ZPaymentFullLogs']['light_plan_amount'] = $litePlanData['amount'];
9812                    $data['ZPaymentFullLogs']['light_plan_price_id'] = $litePlanData['priceId'];
9813
9814                    // change payment plan id and price id
9815                    $user['price_id'] = $litePlanData['priceId'];
9816                    $user['payment_plan_id'] = $litePlanData['paymentPlanId'];
9817                    $user['paymentAmount'] = $lightPlanAmount + $receivablePayment + $appreciationReceivable + $liveLessonReceivable - $annualDiscountOptionAmount;
9818
9819                    // change the money 
9820                    $data['ZPaymentFullLogs']['money'] = $litePlanData['amount'];
9821                    $data['ZPaymentFullLogs']['formType'] = $formType;
9822
9823                    // add annual discount option
9824                    if (
9825                        $annualDiscountOptionData &&
9826                        $paymentPlanType == Configure::read('register_plan_types.premium_with_annual_discount_option')
9827                    ) {
9828                        $data['discountOption'] = $user['discountOption'] = $annualDiscountOptionData;
9829                    }
9830
9831                    // NJ-32737
9832                    $membershipStatusIndex = UserTable::getStudentMembershipStatus($user['id']);
9833                    if (in_array($membershipStatusIndex, Configure::read('allow_coupon.settlement')) &&
9834                        isset($data['z_payment_form_type']) &&
9835                        in_array($data['z_payment_form_type'], Configure::read('allow_coupon.settlement_form_type'))
9836                    ) {
9837                        if (isset($couponData['useCouponAmount']) && $couponData['useCouponAmount'] > 0) {
9838                            if ($data['ZPaymentFullLogs']['money'] >= $couponData['useCouponAmount']) {
9839                                $data['ZPaymentFullLogs']['money'] -= $couponData['useCouponAmount'];
9840                            } else {
9841                                $data['ZPaymentFullLogs']['money'] = 0;
9842                            }
9843
9844                            $user['couponUseSettlement'] = $couponData;
9845
9846                            // payment amount - coupon amount
9847                            $user['paymentAmount'] = $data['ZPaymentFullLogs']['money'];
9848
9849                        }
9850                    }
9851                    // NJ-32737-end
9852
9853                    $npt = $this->createPaymentTransaction($formType, $user);
9854                    
9855                    // 
9856                    if ($npt) {
9857                        // add payment hash
9858                        $data['ZPaymentFullLogs']['paymentHash'] = $npt['payment_hash'];
9859                    }else{
9860                        $this->set('transactionError', 1);
9861                    }
9862                }
9863
9864            }else{
9865                $npt = true;
9866            }
9867
9868            if($corporateIndiUser) {
9869                if ($corporateIndiPaymentData = $this->Session->read('PaymentCreditChargeCorporateData')) {
9870                    $corporatePaymentAmount = $corporateIndiPaymentData['paymentAmount'];
9871                    $data['ZPaymentFullLogs']['money'] = (int)$corporatePaymentAmount;
9872                }
9873            }
9874
9875            $this->log(__METHOD__ . '[NJ-18780] > form type ' . json_encode($formType), 'paypal_debug');
9876            $this->log(__METHOD__ . '[NJ-18780] > data '. json_encode($data), 'paypal_debug');
9877
9878            if ($npt) {
9879
9880                // NJ-25522: Skip confirm page if using 3D secure challenge
9881                $zeus3DSecureChallengeFlg = $this->memcache->get('zeus3DSecureChallengeFlg_' . $user['id']);
9882
9883                $user['price_id'] = $ppData['priceId'];
9884                $user['payment_plan_id'] = $ppData['paymentPlanId'];
9885                $user['paymentAmount'] = $ppData['amount'] + $receivablePayment + $appreciationReceivable + $liveLessonReceivable - $annualDiscountOptionAmount;
9886
9887                if(!$zeus3DSecureChallengeFlg && $corporateIndiUser) {
9888                    $corpIndiPT = $this->createCorporateIndividualPayment($data);
9889                    $data['ZPaymentFullLogs']['paymentHash'] = $corpIndiPT['paymentHash'];
9890                    $data['ZPaymentFullLogs']['money'] = $corpIndiPT['paymentAmount'];
9891                }
9892
9893                $this->Session->write('PaymentCreditChargeInfo', $data);
9894
9895                if ($zeus3DSecureChallengeFlg) {
9896                    $formType = isset($data['ZPaymentFullLogs']['formType']) ? $data['ZPaymentFullLogs']['formType'] : Configure::read('payment_credit_force_charge');
9897
9898                    if($corporateIndiUser) {
9899                        $data['ZPaymentFullLogs']['paymentHash'] = $this->Session->read('indiCorpPaymentHash') ?? '';
9900                    }
9901
9902                    // if corporate credit charge
9903                    if (
9904                        $formType != Configure::read('payment_credit_force_charge') && 
9905                        !$litePlanFlg &&
9906                        !$chocottoPlanFlg
9907                    ) {
9908                        if ($corporateIndiPaymentData = $this->Session->read('PaymentCreditChargeCorporateData')) {
9909                            $corporatePaymentAmount = $corporateIndiPaymentData['paymentAmount'];
9910                            $data['ZPaymentFullLogs']['money'] = (int)$corporatePaymentAmount;
9911                        }
9912                    }
9913                    $referrer = array('controller' => 'Payment', 'action' => 'payment_credit_charge');
9914                    $this->z_start($data, $formType, $referrer);
9915                }
9916
9917                // - NJ-23812: write session to skip and auto charge check
9918                $this->Session->write('credit_skip_to_confirmation',true);
9919                return $this->redirect(myTools::getUrl() . '/payment/payment_credit_charge_confirm');
9920            }
9921
9922        } else {
9923            $data = $this->Session->read('PaymentCreditChargeInfo');
9924            $this->set('data', $data);
9925        }
9926
9927        // clear previously set tokens and set new token
9928        $this->unsetToken();
9929        $token = md5 (uniqid (rand (), true));
9930        $this->Session->write('Payment.token', $token);
9931        $comPlanUser = false;
9932        $isFreeFlg = false;
9933        $freeNumber = 0;
9934        $userId = $user['id'];
9935
9936        // if has complimentary code
9937        if (isset($user['complimentary_code'])) {
9938            // set com_plan_user to true if payment plan id is not null and is complimentary plan
9939            if (isset($user['payment_plan_id']) && $user['payment_plan_id'] == Configure::read('payment_plans.complimentary_plan')){
9940                $comPlanUser = $user['com_plan_user'] = true;
9941            // set com_plan_user to true if payment plan id is null and is complimentary plan
9942            } elseif (!isset($user['payment_plan_id']) && $this->Payment->ifComPlanUser($user['id'])) {
9943                $comPlanUser = $user['com_plan_user'] = true;
9944            }
9945        }
9946    
9947        // delete session
9948        if ($this->Session->check($corpSessionKey)) {
9949            $this->Session->delete($corpSessionKey);
9950        }
9951
9952        // check if corporate user
9953        if (!$corporateIndiUser) {
9954            // change payment plan id and price id
9955            $user['price_id'] = $ppData['priceId'];
9956            $user['payment_plan_id'] = $ppData['paymentPlanId'];
9957            $user['paymentAmount'] = $ppData['amount'] + $receivablePayment + $appreciationReceivable + $liveLessonReceivable;
9958
9959            $user = $this->changePaymentPlanIfTelecomUser($user);
9960
9961            // - NJ-23812: write session to skip and auto charge check
9962            // set transaction error to 1 if failed to create payment transaction
9963            if (!$pt = $this->createPaymentTransaction($formType, $user)) {
9964                $this->set('transactionError', 1);
9965            }
9966        }
9967        
9968        if (isset($cpData)) {
9969            $this->set('cpFormatAmount', $cfAmount);
9970            // $this->set('cRawAmount',$cRawAmount);
9971        }
9972
9973        // -------  NJ-23812 : set support skip paypal confirmation
9974
9975        $sessionPaypalParams = array(
9976            'token' => $token,
9977            'payment_gateway_type' => Configure::read('card_company.paypal'),
9978            'ZPaymentFullLogs' => array(
9979                'retainIndiPlan' => $corporateIndiUser,
9980                'paymentHash' => isset($pt['payment_hash']) ? $pt['payment_hash'] : "",
9981                'money' => $ppData['amount']
9982            ),
9983            'paymentPlanData' => $ppData,
9984            'receivablePayment' => $receivablePayment,
9985            'appreciationReceivable' => $appreciationReceivable,
9986            'liveLessonReceivable' => $liveLessonReceivable,
9987            'formType' => $formType
9988        );
9989
9990        $this->Session->write('paypalPaymentCreditChargeData', $sessionPaypalParams);
9991
9992        $this->setSupportPayPal($user);
9993        $this->set('paypalUserData', $user);
9994        $this->set('userApiToken', $user['api_token']);
9995
9996        $currencyData = $this->Currency->getSymbolAndPosition($user['currency_code']);
9997        $this->set('monthlyPrice',myTools::customFormatAmount($ppData['amount'], $user['currency_code']));
9998        $this->set('monthylyPriceNoTax', myTools::formatAmount($ppData['amountConstTaxDeducted']));
9999        $this->set('monthlyPriceSymbol',myTools::getCurrencySymbol($user['currency_code']));
10000
10001        // ----------- NJ-23812 : support end 
10002
10003        $this->set('ppAmount', $ppData['amount']);
10004        $this->set('ppFormatAmount', $ppData['fAmount']);
10005        $this->set('corporateIndiUser', $corporateIndiUser);
10006        $this->set('comPlanUser', $comPlanUser);
10007        $this->set('token', $token);
10008        $this->set('title_for_layout', '再入会手続き|オンライン英会話のネイティブキャンプ');
10009        $this->set('zeusTransactionFlag', true);
10010        $this->set('paymentHash', isset($pt['payment_hash']) ? $pt['payment_hash'] : "");
10011        $this->set('corporateType', myTools::getCoporateTypeUsingPaymentPlanId($user['payment_plan_id']));
10012        $this->set('isFreeFlg', $isFreeFlg);
10013        $this->set('freeNumber', $freeNumber);
10014        $this->set('currencyCode', $currencyCode);
10015        $this->setPaymentViewVars();
10016        
10017        $comp_plan_page = 'credit_charge';
10018        if ($comPlanUser) {
10019            $comp_plan_page = "not_allowed_lite_plan_change";
10020            $ccData = $this->ComplimentaryCode->find('first', 
10021            array(
10022                'fields' => array('available_days','template_type'),
10023                'conditions' => array(
10024                    'code' => $user['complimentary_code'],
10025                    'template_type !=' => 0 // not trial
10026                )
10027            ));
10028
10029            if ($ccData) {
10030                $comp_plan_page = 'credit_charge';
10031            }
10032
10033            $this->User->clear();
10034        
10035            $_paymentPlanID =     $this->User->read(array('payment_plan_id'), $user['id']);
10036            $_paymentPlanID = $_paymentPlanID['User']['payment_plan_id'];
10037
10038            // -> update the correct complimentary payment plan id
10039            $user['payment_plan_id'] = $_paymentPlanID;
10040        }
10041
10042        // - NJ-18780 : set view var for lite plan description 
10043        $this->setLitePaymentInfoView($user,true,false,$comp_plan_page);
10044
10045        if ($this->RequestHandler->isMobile()) {
10046            $this->layout = ('mobile');
10047            $this->render('/Mobile/Payment/payment_credit_charge');
10048        }
10049    }
10050
10051    private function wp_credit_charge() {
10052        // set variables
10053        $userData = $this->sharedUserData['User'];
10054        $apiToken = $userData['api_token'];
10055        $memKey = "pc_wp_charge_card_type_{$apiToken}";
10056        $memData = $this->memcache->get($memKey);
10057        $cardType = isset($memData['cardType']) ? $memData['cardType'] : 0;
10058
10059        // - NJ-23812
10060        if ($this->Session->read('credit_skip_to_confirmation')) {
10061            $this->Session->delete('credit_skip_to_confirmation');
10062        }
10063
10064        // redirect to form page if previously child and parent unsubsribed
10065        if ( 
10066            (empty($userData['card_company']) && empty($userData['card_brand']) && empty($userData['card_token']) && empty($userData['card_number'])) ||
10067            ($userData['card_brand'] == 'AFTEE2' && empty($userData['card_company']))
10068        ) {
10069            $this->memcacheCardType(array(
10070                'key' => $memKey,
10071                'value' => array('cardType' => $cardType)
10072            ));
10073            return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/payment/wp_credit_charge_form");
10074        }
10075
10076        // get payment data
10077        $pData = $this->PaymentPlanPrice->getPaymentData(array(
10078            'currencyCode' => $userData['currency_code'],
10079            'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
10080            'logFileName' => 'card_charge'
10081        ));
10082
10083        // redirect to mypage if premium plan payment is not supported
10084        if (!isset($pData)) {
10085            return $this->redirect('/');
10086        }
10087
10088        if ($this->request->is('post')) {
10089            $cardType = $this->request->data['cardType'];
10090
10091            // memcache card type value
10092            $this->memcacheCardType(array(
10093                'key' => $memKey,
10094                'value' => array('cardType' => $cardType)
10095            ));
10096
10097            // redirect to hosted page if using new card ($cardType = 1)
10098            if ($cardType) {
10099                return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/payment/wp_credit_charge_form");
10100            // redirect to confirm page if using existing card ($cardType = 0)
10101            } else {
10102
10103                // - NJ-23812: write session to skip and auto charge 
10104                $this->Session->write('credit_skip_to_confirmation',true);
10105
10106                return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/payment/payment_credit_charge_confirm");
10107            }
10108        }
10109
10110        /* check if there is error during payment process */
10111        if ($errorType = isset($this->request->query['wpErrType']) ? $this->request->query['wpErrType'] : null) {
10112            if ($error = myTools::getWorldpayErrorMsg($errorType)) {
10113                $this->set('error', $error);
10114            }
10115        } else {
10116            $memKeyError = 'pc_wp_charge_error_'. $apiToken;
10117            if ($error = $this->memcache->get($memKeyError)) {
10118                $this->set('error', $error);
10119
10120                // delete memcache error
10121                $this->memcache->delete($memKeyError);
10122            }
10123        }
10124
10125        // check if allowed aftee
10126        $this->checkAfteeSupported($this->sharedUserData['User'],true);
10127    
10128            // set view variables
10129        $this->set('pmtValue', 'payment');
10130        $this->set('apiToken', $apiToken);
10131        $this->set('logFileName', 'card_charge');
10132        $this->set('nc_terminal_type', 1); // pc
10133        $this->set('memKeyError', 'pc_wp_charge_error_'.$apiToken);
10134        $this->set('formType', Configure::read("payment_credit_force_charge"));
10135        $this->set('referrer', urlencode(myTools::getUrl(). "/{$this->localizeDir}/payment/payment_credit_charge"));
10136        $this->set('successUrl', urlencode( myTools::getUrl() . "/{$this->localizeDir}/payment/payment_credit_charge_complete"));
10137
10138        $isCardRegistered = (!empty($userData['card_brand']) && !empty($userData['card_number'])) ? true : false;
10139
10140        // ------- end NJ-23812 ------------------------------
10141
10142        // set view variables
10143        $this->set('comPlanUser', $this->ifComPlanUser($userData));
10144        $this->set('cardLogo', myTools::getWorldpayCardLogo($userData['card_brand']));
10145        $this->set('cardType', $cardType);
10146        $this->set('cardBrand', $userData['card_brand']);
10147        $this->set('cardNumber', $userData['card_number']);
10148        $this->set('fAmount', $pData['fAmount']);
10149        $this->set('ppAmount', $pData['amount']);
10150        $this->set('isCardRegistered', $isCardRegistered);
10151
10152        $currencyData = $this->Currency->getSymbolAndPosition($userData['currency_code']);
10153        $this->set('monthlyPrice', myTools::customFormatAmount($pData['amount'], $userData['currency_code']));
10154        $this->set('monthylyPriceNoTax', myTools::formatAmount($pData['amountConstTaxDeducted']));
10155        $this->set('monthlyPriceSymbol',myTools::getCurrencySymbol($userData['currency_code']));
10156
10157
10158        if ($this->RequestHandler->isMobile()) {
10159            $this->layout = ('mobile');
10160            $this->render('/Mobile/Payment/wp_payment_credit_charge');
10161        } else {
10162            $this->render('/Payment/wp_payment_credit_charge');
10163        }
10164    }
10165    /**
10166     * @api {get} /:language/payment/payment_credit_charge_confirm payment_credit_charge_confirm()
10167     * @apiName payment_credit_charge_confirm
10168     * @apiGroup Payment
10169     * @apiDescription This endpoint is used to display the payment confirmation page for credit charge.
10170     * 
10171     * @apiParam {String} language Language code of the user
10172     * 
10173     * @apiSuccess {View} Render Displays the payment confirmation page for credit charge.
10174     * @apiSuccess {View} Redirect Redirect to zeus credit charge confirm function if currency is equals to jpy.
10175     * @apiSuccess {View} Redirect Redirect to wp credit charge confirm function if currency is not equals to jpy.
10176     * 
10177     * @apiSuccessExample Success Response:
10178     * Display the payment confirmation page for credit card payment.
10179     * 
10180     * @apiSuccessExample Redirect Response if currency is equals to jpy:
10181     * Redirect to zeus_credit_charge_confirm() function.
10182     * 
10183     * @apiSuccessExample Redirect Response if currency is not equals to jpy:
10184     * Redirect to wp_credit_charge_confirm() function.
10185     * 
10186     * @apiSampleRequest off
10187     */
10188    public function payment_credit_charge_confirm() {
10189        $this->checkUser(Configure::read('payment_credit_force_charge'));
10190
10191        // redirect to zeus process if currency is equals to jpy
10192        if ($this->sharedUserData['User']['currency_code'] == Configure::read('default.user_currency')) {
10193            $this->zeus_credit_charge_confirm();
10194        // redirect to wp
10195        } else {
10196            $this->wp_credit_charge_confirm();
10197        }
10198
10199    }
10200
10201    /**
10202     * @api {post} /payment/retrial_confiscate_coins/:formType/:userId/:paymentPlanId retrial_confiscate_coins()
10203     * @apiName retrial_confiscate_coins
10204     * @apiGroup Payment
10205     * @apiDescription This endpoint is used to confiscate coins for retrial users.
10206     * 
10207     * @apiParam {String} formType Form type of the user
10208     * @apiParam {Number} userId User ID of the user
10209     * @apiParam {Number} paymentPlanId Payment plan ID of the user
10210     * 
10211     * @apiSuccess {Boolean} true Returns true if the coins are confiscated successfully.
10212     *
10213     * @apiError {Boolean} false Returns false if the coins are not confiscated successfully.
10214     * 
10215     * @apiSuccessExample Success Response:
10216     * true
10217     * 
10218     * @apiErrorExample Error Response:
10219     * false
10220     */
10221    public function retrial_confiscate_coins($params = []) {
10222
10223        if (
10224            isset($params['formType']) &&
10225            isset($params['userId']) &&
10226            isset($params['paymentPlanId']) &&
10227            (
10228                (    $params['formType'] == Configure::read('payment_credit_authentication') &&
10229                    $params['paymentPlanId'] = Configure::read('payment_plans.free_trial')
10230                ) || 
10231                (
10232                    $params['formType'] == Configure::read('payment_lite_credit_free') &&
10233                    $params['paymentPlanId'] = Configure::read('payment_plans.light_plan_free')
10234                )
10235            )
10236        ) {
10237
10238            $reEnroll = $this->UsersDeactivationEnquate->find('first', [
10239                'fields' => array('membership_type', 'deactivation_type'),
10240                'conditions' => array(
10241                    'UsersDeactivationEnquate.user_id' => $params['userId'],
10242                    'OR' => array(
10243                        'UsersDeactivationEnquate.membership_type' => [
10244                            Configure::read('student_status_type.sapuri'),
10245                            Configure::read('student_status_type.card_auth')
10246                        ],
10247                        'UsersDeactivationEnquate.deactivation_type' => Configure::read('deactivation_type.retrial_grantee')
10248                        )
10249                ),
10250                'order' => 'UsersDeactivationEnquate.created DESC'
10251            ]);
10252
10253            if (!empty($reEnroll)) {
10254
10255                // Step 1: Retrieve the user's current MC coin balance
10256                $_monthlyPoints = $this->UsersPoint->getCurrentUserMCPoint($params['userId']); // MC = Monthly Coin
10257
10258                // Step 2: Confiscate existing MC coins if the user has a positive balance
10259                if (is_numeric($_monthlyPoints) && (int) $_monthlyPoints > 0) {
10260                    $_confiscateParams = array(
10261                        'userId' => $params['userId'],
10262                        'point' => $_monthlyPoints,
10263                        'kbn' => 18, // Administrator Change/Minus
10264                        'coinType' => 3
10265                    );
10266
10267                    // Apply the confiscation of MC coins
10268                    $this->UsersPoint->confiscateUserLitePoints($_confiscateParams);
10269                }
10270
10271                // Step 3: Grant bonus coins as part of re-enrollment (retrial)
10272                $reEnroll = $reEnroll['UsersDeactivationEnquate'];
10273
10274                UsersPointTable::giveBonusCoins([
10275                    'userId' => $params['userId'],
10276                    'triggerNo' => 5,
10277                    'usersDeactivationEnquateMembershipType' => isset($reEnroll['membership_type']) && $reEnroll['membership_type'] ? $reEnroll['membership_type'] : null,
10278                    'adminGrantRetrial' => $reEnroll['deactivation_type'] == '2' ? true : false
10279                ]);
10280            }
10281        }
10282    }
10283
10284
10285
10286    private function zeus_credit_charge_confirm() {
10287        // redirect to top page if zeuspay info does not exist
10288        if (!$data = $this->Session->read('PaymentCreditChargeInfo')) {
10289            return $this->redirect(myTools::getUrl() . '/');
10290        }
10291
10292        $isFreeFlg = false;
10293        $lessonLimit = 0;
10294        $monthlyFee = 0;
10295        $freeNumber = 0;
10296        $retainAsCorporateUser = false;
10297        $indiCorpTypeLight = false;
10298        $fAmount = myTools::formatAmount($data['ZPaymentFullLogs']['money']);
10299        $corporatePaymentAmount = 0;
10300        $userData = $this->sharedUserData['User'];
10301
10302        // if corporate and retain corporate individual plan
10303        if (isset($userData['corporate_id']) && $userData['corporate_id']) {
10304            $retainAsCorporateUser = true;
10305            // get corporate user session data
10306            if ($corporateIndiPaymentData = $this->Session->read('PaymentCreditChargeCorporateData')) {
10307                $fAmount = $corporateIndiPaymentData['fAmount'];
10308                $corporatePaymentAmount = $corporateIndiPaymentData['paymentAmount'];
10309
10310                // if corporate light
10311                if ($data['ZPaymentFullLogs']['indiCorpType'] == Configure::read('corporate_type.light')) {
10312                    $indiCorpTypeLight = true;
10313                    $isFreeFlg = $corporateIndiPaymentData['freeFlg'];
10314                    $monthlyFee = $corporateIndiPaymentData['monthlyFee'];
10315                    $freeNumber = $corporateIndiPaymentData['freeNumber'];
10316                    $lessonLimit = $corporateIndiPaymentData['lessonLimit'];
10317                }
10318            }
10319        }
10320
10321        $readSkipConfirmation = $this->Session->read('credit_skip_to_confirmation');
10322
10323        if ($readSkipConfirmation) {
10324            $this->Session->delete('credit_skip_to_confirmation');
10325        }
10326
10327        if ($this->request->is('post') || $readSkipConfirmation) {
10328            // check if token matches token in session
10329            $checkToken = $this->checkToken($data['token']);
10330
10331            // check if token is true
10332            if ($checkToken) {
10333                // unset previously set tokens
10334                $this->unsetToken();
10335                $formType = isset($data['ZPaymentFullLogs']['formType']) ? $data['ZPaymentFullLogs']['formType'] : Configure::read('payment_credit_force_charge');
10336
10337                $isLitePlan = (isset($data['ZPaymentFullLogs']['payment_plan_type']) && (int) $data['ZPaymentFullLogs']['payment_plan_type'] == 1) ? true : false;
10338
10339                $isChocottoPlan = (
10340                    isset($data['ZPaymentFullLogs']['payment_plan_type']) &&
10341                    $data['ZPaymentFullLogs']['payment_plan_type'] == Configure::read('register_plan_types.chocotto')
10342                );
10343
10344                // if corporate credit charge
10345                if ($formType != Configure::read('payment_credit_force_charge') && !$isLitePlan && !$isChocottoPlan) {
10346                    $data['ZPaymentFullLogs']['money'] = (int)$corporatePaymentAmount;
10347                }
10348
10349                $referrer = array('controller' => 'Payment', 'action' => 'payment_credit_charge');
10350                $this->z_start($data, $formType, $referrer);
10351            }
10352        }
10353
10354        if (isset($data['ZPaymentFullLogs']['cardnumber']) && !empty($data['ZPaymentFullLogs']['cardnumber'])) {
10355            $cardNumberArr = str_split($data['ZPaymentFullLogs']['cardnumber'], 4);
10356            $this->set('cardNumber', end($cardNumberArr));
10357        } else {
10358            $this->getAndSetCardInfo($userData);
10359        }
10360
10361        // - set view vars
10362        $this->set('monthlyPriceSymbol', myTools::getCurrencySymbol($userData['currency_code']));
10363        $this->set('fAmount', $fAmount);
10364        $this->set('indiCorpTypeLight', $indiCorpTypeLight);
10365        $this->set('lessonLimit', $lessonLimit);
10366        $this->set('isFreeFlg', $isFreeFlg);
10367        $this->set('freeNumber', $freeNumber);
10368        $this->set('monthlyFee', $monthlyFee);
10369        $this->set('corporateType', $data['ZPaymentFullLogs']['indiCorpType']);
10370        $this->set('retainAsCorporateUser', $retainAsCorporateUser);
10371
10372        if ($this->RequestHandler->isMobile()) {
10373            $this->layout = ('mobile');
10374            $this->render('/Mobile/Payment/payment_credit_charge_confirm');
10375        }
10376    }
10377
10378    private function wp_credit_charge_confirm() {
10379        $this->response->disableCache();
10380        // set variables
10381        $logFileName = 'card_charge';
10382        $formType = Configure::read('payment_credit_force_charge');
10383        $userData = $this->sharedUserData['User'];
10384        $currencyCode = $userData['currency_code'];
10385        $userId = $userData['id'];
10386        $apiToken = $userData['api_token'];
10387
10388        $readSkipConfirmation = $this->Session->read('credit_skip_to_confirmation');
10389        if ($readSkipConfirmation){
10390            $this->Session->delete('credit_skip_to_confirmation');
10391        }
10392
10393        $memKey = "pc_wp_charge_card_type_{$apiToken}";
10394        // redirect to mypage if memcache card type is not set
10395        if (!$this->memcache->get($memKey)) {
10396            return $this->redirect('/');
10397        }
10398
10399        // get payment data
10400        $pData = $this->PaymentPlanPrice->getPaymentData(array(
10401            'currencyCode' => $currencyCode,
10402            'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
10403            'logFileName' => $logFileName
10404        ));
10405
10406        // redirect to mypage if premium plan not supported
10407        if (!$pData) {
10408            return $this->redirect('/');
10409        }
10410
10411        $userData['com_plan_user'] = $this->ifComPlanUser($userData);
10412        $userData['payment_plan_id'] = $pData['paymentPlanId'];
10413        $userData['price_id'] = $pData['priceId'];
10414        $memKeySkipCharge = "pc_wp_charge_card_type_skip_confirm_{$apiToken}";
10415
10416        if ($this->request->is('post') || $readSkipConfirmation) {
10417            // get reserve payment receivable
10418            $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userId);
10419
10420            // get appreciation payment receivable
10421            $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('appreciation_data.payment_element_type'));
10422
10423            // get live lesson payment receivable    
10424            $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.live'));
10425
10426            // add force charge payment and receivable payment amount
10427            $totalAmount = $pData['amount'] + $receivablePayment + $appreciationReceivable + $liveLessonReceivable;
10428
10429            // NJ-32737
10430            $couponData = $this->Session->read('apply_coupon_usage_data');
10431
10432            $membershipStatusIndex = UserTable::getStudentMembershipStatus($userData['id']);
10433            if (in_array($membershipStatusIndex, Configure::read('allow_coupon.settlement')) &&
10434                isset($formType) &&
10435                in_array($formType, Configure::read('allow_coupon.settlement_form_type'))
10436            ) {
10437                if (isset($couponData['useCouponAmount']) && $couponData['useCouponAmount'] > 0) {
10438                    if ($totalAmount >= $couponData['useCouponAmount']) {
10439                        $totalAmount -= $couponData['useCouponAmount'];
10440                    } else {
10441                        $totalAmount = 0;
10442                    }
10443
10444                    $userData['couponUseSettlement'] = $couponData;
10445                }
10446            }
10447            // NJ-32737-end
10448
10449            $paymentMethodType = myTools::getWPPaymentMethodType($userData['card_brand'], 'payment');
10450            $merchantCode = myTools::getWPMerchantCode($paymentMethodType);
10451            $paymentMethod = explode('_', $paymentMethodType);
10452            $paymentMethod = isset($paymentMethod[0]) ? $paymentMethod[0] : null;
10453            $orderCode = myTools::generateOrderCode($userId);
10454            $currencyExponents = Configure::read('worldpay.currency_exponents');
10455            $exponent = $currencyExponents[$currencyCode];
10456
10457            // get total amount with checking currency exponent
10458            $totalAmountArr = myTools::wpGetAmount($exponent, $totalAmount);
10459            $ncAmount = $totalAmountArr['ncAmount'];
10460            $wpAmount = $totalAmountArr['wpAmount'];
10461
10462            $wpData = array(
10463                'cardToken' => $userData['card_token'],
10464                'merchantCode' => $merchantCode,
10465                'paymentHash' => $orderCode,
10466                'wpPaymentAmount' => $wpAmount
10467            );
10468
10469            // set payment amount
10470            $userData['paymentAmount'] = $ncAmount;
10471
10472            // create payment transaction
10473            if (!$pt = $this->createPaymentTransaction($formType, $userData, $wpData)) {
10474                $this->log(__METHOD__ .' Failed to save payment transaction. Params --> ' . json_encode($wpData), $logFileName);
10475                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to save payment transaction. Params --> ' . json_encode($wpData), 'error');
10476                return $this->redirect('/');
10477            }
10478
10479            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - After save payment transaction. Params --> ' . json_encode($wpData), 'error');
10480
10481            // if aftee payment
10482            if ($userData['card_company'] == Configure::read('card_company.aftee') || ($userData['card_brand'] == "AFTEE" && !empty($userData['aftee_transaction_identifier']))) {
10483
10484                if (!class_exists('AfteePaymentService')) {
10485                    App::uses('AfteePaymentService','Lib');
10486                }
10487                $afteeService = new AfteePaymentService();
10488                $afteeChecksumData = array(
10489                    'shopItemId' => "AFTEE" . $formType,
10490                    'itemName' => 'CreditForceChargeUsingExistingCard',
10491                    'itemPrice' => $totalAmount,
10492                    'itemCount' => 1,
10493                    'customerPhoneNumber' => $userData['phone_number'],
10494                    'customerEmail' => $userData['email'],
10495                    'shopTransactionNo' => $orderCode,
10496                    'userID' =>  $userData['id']
10497                );
10498                $checksum = $afteeService->generateChecksum($afteeChecksumData, false);
10499                $afteeData = array(
10500                    'authentication_token' => $userData['card_token'],
10501                    'related_id' => $userData['aftee_transaction_identifier'],
10502                    'checksum' => $checksum['checksum'],
10503                    'shop_transaction_no' => $orderCode,
10504                    'transaction_options' => array(1)
10505                );
10506        
10507                $afteePaymentData = array_merge($afteeData, $checksum['settlementData']);
10508    
10509                // aftee execute payment
10510                $receivableResult = $afteeService->directPayment($afteePaymentData);
10511                $checkRes = json_decode($receivableResult, true);
10512
10513
10514                if ( isset($checkRes['object']) && $checkRes['object'] == 'transaction') {
10515                    $prPaymentSuccess = true;
10516                } else if ( !array_key_exists("object", $checkRes) || (isset($checkRes['object']) && $checkRes['object'] == 'error')) {
10517                    $prPaymentSuccess = false;
10518                }
10519
10520                // set user model
10521                $uModel = $this->User;
10522                $dataSource = $uModel->getDataSource();
10523                $dataSource->begin();
10524
10525                $afteeTransactionIdentifier = isset($checkRes['id']) && !empty($checkRes['id']) ? $checkRes['id'] : NULL;
10526                if (isset($checkRes['related_transaction']) && !empty($checkRes['related_transaction'])) {
10527                    $afteeTransactionIdentifier = $checkRes['related_transaction'];
10528                }
10529                $orderCode = isset($checkRes['shop_transaction_no']) && !empty($checkRes['shop_transaction_no']) ? $checkRes['shop_transaction_no'] : NULL;
10530                $checkRes['OrderCode'] = $orderCode;
10531
10532                // payment transaction additional data
10533                $checkRes['OrderCode'] = $orderCode;
10534                $checkRes['authentication_token'] = $userData['card_token'];
10535                $checkRes['customer']['phone_number'] = $userData['phone_number'];
10536
10537                // process payment data
10538                if ($prPaymentSuccess) {
10539                    $afteeParams = array(
10540                        'data' => $checkRes,
10541                        'ptData' => $pt,
10542                        'logFileName' => $logFileName,
10543                        'dataSource' => $dataSource,
10544                        'amount' => $pData['amount'],
10545                        'userData' => $userData,
10546                        'receivablePayment' => $receivablePayment,
10547                        'appreciationReceivable' => $appreciationReceivable,
10548                        'liveLessonReceivable' => $liveLessonReceivable,
10549                        'transactionIdentifier' => $afteeTransactionIdentifier,
10550                        'aftee' => 1
10551                    );
10552    
10553                    $this->processAfteePayment($afteeParams);
10554                }
10555
10556                // update payment transaction
10557                $updateData = array(
10558                    'id' => $pt['id'],
10559                    'fields' => array(
10560                        'status' => $prPaymentSuccess,
10561                        'response_text' => array('aftee_directPayment_response' => $receivableResult))
10562                );
10563
10564                // update payment transaction
10565                $this->PaymentTransaction->updateAfteePaymentTransaction($updateData);
10566
10567
10568                // redirect to payment_credit_charge with error display if direct payment response is not authorised
10569                if (!$prPaymentSuccess) {
10570                    if (!class_exists('myMemcached')) {
10571                        App::uses('myMemcached', 'Lib');
10572                    }
10573                    $memKeyError = 'pc_wp_charge_error_' . $apiToken;
10574                    $memerror = __('トランザクションを完了できません。 もう一度お試しください。');
10575                    $memcached = new myMemcached();
10576                    $memcached->set(array(
10577                        'key' => $memKeyError,
10578                        'value' => $memerror,
10579                        'expire' => 3600 // 1 hour
10580                    ));
10581                    return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/payment/payment_credit_charge");
10582                }
10583
10584
10585            // default worldpay payment
10586            } else {
10587
10588                $wpData = array(
10589                    'merchantCode' => $merchantCode,
10590                    'orderCode' => $orderCode,
10591                    'description' => 'Credit Force Charge Using Existing Card',
10592                    'currencyCode' => $currencyCode,
10593                    'exponent' => $exponent,
10594                    'amount' => $wpAmount,
10595                    'cardToken' => $userData['card_token'],
10596                    'email' => $userData['email'],
10597                    'authenticatedShopperId' => $userId,
10598                    'xmlName' => 'direct_payment_with_token',
10599                    'shopperIpAddress' => $_SERVER["REMOTE_ADDR"],
10600                    'wpTransactionIdentifier' => $userData['wp_transaction_identifier'],
10601                    'paymentMethod' => $paymentMethod
10602                );
10603
10604                $result = wpPaymentService::directPayment($wpData);
10605
10606                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - directPayment result --> ' . json_encode($result), 'error');
10607
10608                $updateData = array(
10609                    'id' => $pt['id'],
10610                    'fields' => array('response_text' => array('directPayment_response' => $result)),
10611                    'logFileName' => $logFileName
10612                );
10613
10614                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - before updatePaymentTransaction result --> ' . json_encode($updateData), 'error');
10615
10616                // update payment transaction direct response.
10617                $this->updatePaymentTransaction($updateData);
10618
10619                // redirect to payment_credit_charge with error display if direct payment response is not authorised
10620                if (!myTools::checkIfWPPaymentResponseIsAuthorised($result)) {
10621                    $params = array(
10622                        'apiToken' => $apiToken,
10623                        'wpResponse' => $result,
10624                        'memKey' => 'pc_wp_charge_error_' . $apiToken
10625                    );
10626                    myTools::parseAndSetWPErrorResponse($params);
10627                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - WP Payment not authorised --> ' . json_encode($params), 'error');
10628                    return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/payment/payment_credit_charge");
10629                }
10630            }
10631
10632            //    NC-7644 Add code reward for re-enroolling with the campaign code
10633            $this->addCoinRewardForReenroll($userData);
10634            
10635            // Teacher Perks : Student re-enroll
10636            ClassRegistry::init('TeacherPerksAccount')->reEnroll(['user_id' => $userData['id']]);
10637
10638            // delete memcache
10639            if ($this->memcache->get($memKey)) {
10640                $this->memcache->delete($memKey);
10641            }
10642
10643            // redirect to complete page
10644            return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/payment/payment_credit_charge_complete");
10645        }
10646
10647        $this->set('monthlyPriceSymbol', myTools::getCurrencySymbol($currencyCode));
10648        $currencyData = $this->Currency->getSymbolAndPosition($currencyCode);
10649        $this->set('monthylyPrice', myTools::addPriceSymbol($pData['fAmount'], $currencyData['symbol'], $currencyData['prefix_suffix_flg']));
10650
10651        // set view variables
10652        $this->set('currencyCode', $currencyCode);
10653        $this->set('cardLogo', myTools::getWorldpayCardLogo($userData['card_brand']));
10654        $this->set('cardBrand', $userData['card_brand']);
10655        $this->set('cardNumber', $userData['card_number']);
10656        $this->set('fAmount', $pData['fAmount']);
10657        $this->set('cardCompany', $userData['card_company']);
10658
10659        if ($this->RequestHandler->isMobile()) {
10660            $this->layout = ('mobile');
10661            $this->render('/Mobile/Payment/wp_payment_credit_charge_confirm');
10662        } else {
10663            $this->render('/Payment/wp_payment_credit_charge_confirm');
10664        }
10665    }
10666    /**
10667     * @api {get} /:language/payment/paypal_payment_credit_charge_confirm paypal_payment_credit_charge_confirm()
10668     * @apiName paypal_payment_credit_charge_confirm
10669     * @apiGroup Payment
10670     * @apiDescription This endpoint is used to display the payment confirmation page for credit charge using paypal.
10671     * 
10672     * @apiParam {String} language Language code of the user
10673     * 
10674     * @apiSuccess {View} Render Displays the payment confirmation page for credit charge using paypal.
10675     * 
10676     * @apiError {View} Redirect Redirect to mypage if paypal payment credit charge data is missing.
10677     * 
10678     * @apiSuccessExample Success Response:
10679     * Display the payment confirmation page for credit card payment using paypal.
10680     * 
10681     * @apiErrorExample Error Response:
10682     * Redirect to mypage if paypal payment credit charge data is missing.
10683     * 
10684     * @apiSampleRequest off
10685     */
10686    public function paypal_payment_credit_charge_confirm() {
10687        $logFileName = 'paypal_debug';
10688        $user = $this->sharedUserData['User'];
10689
10690        $data = $this->Session->read('paypalPaymentCreditChargeData');
10691        if (!$data) {
10692            $this->log(__METHOD__ . ' Missing paypal payment credit charge data. --> ' . json_encode($data) . ' | user id  --> ' . json_encode($user['id']), $logFileName);
10693            return $this->redirect(myTools::getUrl());
10694        }
10695
10696        $this->set('fAmount', myTools::formatAmount($data['ZPaymentFullLogs']['money']));
10697        $this->set('monthlyPriceSymbol', myTools::getCurrencySymbol($user['currency_code']));
10698        $this->set('paypalUserData', $user);
10699        $this->set('userApiToken', $user['api_token']);
10700
10701        // set payment gateway type
10702        $this->memcache->set(array(
10703            'key' => 'creditChargePaymentGatewayType_' . $user['api_token'],
10704            'value' => $data['payment_gateway_type'],
10705            'expire' => 3600 // 1 hour
10706        ));
10707
10708        if ($this->RequestHandler->isMobile()) {
10709            $this->layout = ('mobile');
10710            $this->render('/Mobile/Payment/paypal_payment_credit_charge_confirm');
10711        }
10712    }
10713    /**
10714     * @api {get} /:language/payment/wp_credit_charge_form wp_credit_charge_form()
10715     * @apiName wp_credit_charge_form
10716     * @apiGroup Payment
10717     * @apiDescription This endpoint is used to redirect to pages after form submission for worldpay credit charge.
10718     * 
10719     * @apiParam {String} language Language code of the user
10720     * 
10721     * @apiSuccess {View} Redirect Redirects to {{ENV}}/payment/payment_credit_charge_complete if the user is not on a complimentary plan.
10722     * @apiSuccess {View} Redirect Redirects to {{ENV}}/payment/coupon_payment_credit_charge_complete if the user is on a complimentary plan.
10723     * 
10724     * @apiError {View} Redirect Redirects to mypage if memcache card type is not set.
10725     * @apiError {View} Redirect Redirects to mypage if premium plan payment is not supported.
10726     * 
10727     * @apiSuccessExample Success Response if user is not on a complimentary plan:
10728     * Redirects to {{ENV}}/payment/payment_credit_charge_complete.
10729     * 
10730     * @apiSuccessExample Success Response if user is on a complimentary plan:
10731     * Redirects to {{ENV}}/payment/coupon_payment_credit_charge_complete.
10732     * 
10733     * @apiErrorExample Error Response if memcache card type is not set:
10734     * Redirects to mypage.
10735     * 
10736     * @apiErrorExample Error Response if premium plan payment is not supported:
10737     * Redirects to mypage.
10738     * 
10739     * @apiSampleRequest off
10740     */
10741    public function wp_credit_charge_form() {
10742        $this->response->disableCache();
10743        $formType = Configure::read('payment_credit_force_charge');
10744        $this->checkUser($formType);
10745        $apiToken = $this->sharedUserData['User']['api_token'];
10746        $userData = $this->sharedUserData['User'];
10747
10748        $memKey = "pc_wp_charge_card_type_{$apiToken}";
10749        // redirect to mypage if memcache card type is not set
10750        if (!$this->memcache->get($memKey)) {
10751            return $this->redirect('/');
10752        }
10753
10754        // - NJ-23812
10755        if ($this->Session->read('credit_skip_to_confirmation')) {
10756            $this->Session->delete('credit_skip_to_confirmation');
10757        }
10758
10759        $this->setPerMonthSymbol($this->localizeDir, true);
10760
10761        // get payment data
10762        $pData = $this->PaymentPlanPrice->getPaymentData(array(
10763            'currencyCode' => $userData['currency_code'],
10764            'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
10765            'logFileName' => 'card_charge'
10766        ));
10767
10768        // redirect to mypage if premium plan payment is not supported
10769        if (!isset($pData)) {
10770            return $this->redirect('/');
10771        }
10772
10773        // check if allowed aftee
10774        $this->checkAfteeSupported($this->sharedUserData['User']);
10775
10776
10777        // - NJ-23812 start support
10778        /* check if there is error during payment process */
10779        if ($errorType = isset($this->request->query['wpErrType']) ? $this->request->query['wpErrType'] : null) {
10780            if ($error = myTools::getWorldpayErrorMsg($errorType)) {
10781                $this->set('error', $error);
10782            }
10783        } else {
10784            $memKeyError = 'pc_wp_charge_error_'. $apiToken;
10785            if ($error = $this->memcache->get($memKeyError)) {
10786                $this->set('error', $error);
10787
10788                // delete memcache error
10789                $this->memcache->delete($memKeyError);
10790            }
10791        }
10792
10793        $comPlanUser = $this->ifComPlanUser($userData);
10794
10795        // set view variables
10796        $this->set('comPlanUser', $comPlanUser);
10797        $this->set('cardLogo', myTools::getWorldpayCardLogo($userData['card_brand']));
10798        $this->set('cardType', $cardType);
10799        $this->set('cardBrand', $userData['card_brand']);
10800        $this->set('cardNumber', $userData['card_number']);
10801        $this->set('fAmount', $pData['fAmount']);
10802        $this->set('ppAmount', $pData['amount']);
10803
10804        $isCardRegistered = (!empty($userData['card_brand']) && !empty($userData['card_number'])) ? true : false;
10805        $this->set('isCardRegistered', $isCardRegistered);
10806
10807
10808        $currencyData = $this->Currency->getSymbolAndPosition($userData['currency_code']);
10809        $this->set('monthlyPrice', myTools::customFormatAmount($pData['amount'], $userData['currency_code']));
10810        $this->set('monthylyPriceNoTax', myTools::formatAmount($pData['amountConstTaxDeducted']));
10811        $this->set('monthlyPriceSymbol',myTools::getCurrencySymbol($userData['currency_code']));
10812
10813        // set view variables
10814        $this->set('pmtValue', 'payment');
10815        $this->set('apiToken', $apiToken);
10816        $this->set('logFileName', 'card_charge');
10817        $this->set('nc_terminal_type', 1); // pc
10818        $this->set('memKeyError', 'pc_wp_charge_error_'.$apiToken);
10819        $this->set('formType', $formType);
10820        $this->set('referrer', urlencode(myTools::getUrl(). "/{$this->localizeDir}/payment/payment_credit_charge"));
10821
10822        // NJ-32737
10823        $this->setCouponUseData($this->sharedUserData['User']['id'], $this->sharedUserData['User']['currency_code']);
10824
10825        // if complimentary plan user
10826        if ($this->ifComPlanUser($this->sharedUserData['User'])) {
10827            $this->set('successUrl', urlencode(myTools::getUrl()."/{$this->localizeDir}/payment/coupon_payment_credit_charge_complete"));
10828        } else {
10829            $this->set('successUrl', urlencode(myTools::getUrl()."/{$this->localizeDir}/payment/payment_credit_charge_complete"));
10830        }
10831        if ($this->RequestHandler->isMobile()) {
10832            $this->layout = ('mobile');
10833            $this->render('/Mobile/Payment/wp_payment_credit_charge');
10834        } 
10835    }
10836    /**
10837     * @api {get} /:language/payment/paypal_payment_credit_charge_process/:token/:negativeTesting/:payment_plan_type paypal_payment_credit_charge_process()
10838     * @apiName paypal_payment_credit_charge_process
10839     * @apiGroup Payment
10840     * @apiDescription This endpoint is used to process the credit charge using paypal.
10841     * 
10842     * @apiParam {String} language Language code of the user
10843     * @apiParam {String} token Token of the user
10844     * @apiParam {Number} negativeTesting Negative testing flag. 1 = true, 0 = false
10845     * @apiParam {Number} payment_plan_type Payment plan type.
10846     * 
10847     * @apiSuccess {View} Redirect Redirects to {{ENV}}/payment/payment_credit_charge_complete if the payment is successful.
10848     * 
10849     * @apiError {View} Redirect Redirects to {{ENV}}/mypage if missing paypal credit charge data
10850     * @apiError {View} Redirect Redirects to {{ENV}}/payment/payment_credit_charge if failed to fetch light plan description
10851     * @apiError {View} Redirect Redirects to {{ENV}}/ if annual discount option does not exist or is not enabled
10852     * @apiError {View} Redirect Redirects to {{ENV}}/payment/payment_credit_charge if failed to fetch chocotto plan description
10853     * @apiError {View} Redirect Redirects to {{ENV}}/payment/payment_credit_charge if paypal settlement is not successful
10854     * 
10855     * @apiSuccessExample Success Response:
10856     * Redirects to {{ENV}}/payment/payment_credit_charge_complete if the payment is successful.
10857     * 
10858     * @apiErrorExample Error Response if missing paypal credit charge data:
10859     * Redirects to {{ENV}}/mypage.
10860     * 
10861     * @apiErrorExample Error Response if failed to fetch light plan description:
10862     * Redirects to {{ENV}}/payment/payment_credit_charge.
10863     * 
10864     * @apiErrorExample Error Response if annual discount option does not exist or is not enabled:
10865     * Redirects to {{ENV}}/.
10866     * 
10867     * @apiErrorExample Error Response if failed to fetch chocotto plan description:
10868     * Redirects to {{ENV}}/payment/payment_credit_charge.
10869     * 
10870     * @apiErrorExample Error Response if paypal settlement is not successful:
10871     * Redirects to {{ENV}}/payment/payment_credit_charge.
10872     * 
10873     * @apiSampleRequest off
10874     */
10875    public function paypal_payment_credit_charge_process() {
10876        $this->autoRender = false;
10877        $this->layout = false;
10878
10879        $logFileName = 'paypal_debug';
10880        $user = $this->sharedUserData['User'];
10881        $userId = $user['id'];
10882        $get = $this->request->query;
10883        $formType = Configure::read('payment_credit_force_charge');
10884
10885        // get session payment credit register data
10886        $data = $this->Session->read('paypalPaymentCreditChargeData');
10887
10888        // redirect to top page if empty
10889        if (!$data) {
10890            $this->log(__METHOD__ . ' Missing paypal payment credit charge data. --> ' . json_encode($data) . ' | user id  --> ' . json_encode($userId), $logFileName);
10891            return $this->redirect(myTools::getUrl());
10892        }
10893
10894        $paymentPlanType = isset($get['payment_plan_type']) ? $get['payment_plan_type'] : 0;
10895
10896        //- pass original payment plan
10897        $userObj = new UserTable($user);
10898        $user['original_status_index'] = $userObj->getMembershipTypeIndex();
10899
10900        if ($paymentPlanType == Configure::read('register_plan_types.light')) {
10901
10902            // fetch light plan description
10903            $litePlanData = $this->PaymentPlanPrice->getPaymentData(array(
10904                'currencyCode' => $user['currency_code'],
10905                'paymentPlanId' => Configure::read('payment_plans.light_plan'),
10906                'logFileName' => 'card_reregister'
10907            ));
10908
10909            if (!$litePlanData) {
10910                $this->Session->setFlash('決済失敗', array("element" => "flashfail"));
10911
10912                $memKey = 'paypalBillingAgreementData_' . $get['token'];
10913
10914                // delete memcache billing agreement data
10915                if ($this->memcache->get($memKey)) {
10916                    $this->memcache->delete($memKey);
10917                }
10918
10919                return $this->redirect(myTools::getUrl('payment/payment_credit_charge'));
10920            }
10921        
10922            $user['price_id'] = $litePlanData['priceId'];
10923            $user['payment_plan_id'] = $litePlanData['paymentPlanId'];
10924        
10925            // - update data 
10926            $data['ZPaymentFullLogs']['money'] = $litePlanData['amount'];
10927            $data['paymentPlanData'] = $litePlanData;
10928            $data['formType'] =  myTools::getLitePlanUserFormType($litePlanData['paymentPlanId']);
10929        } elseif ($paymentPlanType == Configure::read('register_plan_types.premium_with_annual_discount_option')) {
10930            $annualDiscountOptionData = $this->DiscountOptionsPrice->getPaymentData(['currencyCode' => $user['currency_code'], 'discountOptionId' => Configure::read('discount_option.annual.plan_id')]);
10931
10932            // redirect to credit page if annual discount option does not exist or is not enabled
10933            if (!$annualDiscountOptionData) {
10934                return $this->redirect('/');
10935            }
10936
10937            unset($annualDiscountOptionData['contract_start']);
10938            $annualDiscountOptionData += [
10939                'dosh_event' => Configure::read('discount_option.dosh_event.annual_discount'),
10940                'dosh_status' => Configure::read('discount_option.dosh_status.monthly_discount')
10941            ];
10942
10943            // update payment transaction (add annual discount option data)
10944            $this->PaymentTransaction->updatePaymentParams(array('paymentHash' => $data['ZPaymentFullLogs']['paymentHash'], 'updateData' => ['annualDiscountOption' => $annualDiscountOptionData]));
10945
10946            $data['discountOption'] = $annualDiscountOptionData;
10947
10948        //- NJ-27262 chocotto plan payment
10949        } elseif ($paymentPlanType == Configure::read('register_plan_types.chocotto')) {
10950            // fetch chocotto plan description
10951            $chocottoPlanData = $this->PaymentPlanPrice->getPaymentData(array(
10952                'currencyCode' => $user['currency_code'],
10953                'paymentPlanId' => Configure::read('payment_plans.chocotto_plan'),
10954                'logFileName' => 'card_reregister'
10955            ));
10956
10957            if (!$chocottoPlanData) {
10958                $this->Session->setFlash(__d('acount', '決済失敗'), array("element" => "flashfail"));
10959
10960                $memKey = 'paypalBillingAgreementData_' . $get['token'];
10961
10962                // delete memcache billing agreement data
10963                if ($this->memcache->get($memKey)) {
10964                    $this->memcache->delete($memKey);
10965                }
10966
10967                return $this->redirect(myTools::getUrl('payment/payment_credit_charge'));
10968            }
10969        
10970            //- NJ-36141: reset daily lesson time if changed to chocotto plan
10971            $this->UsersDetail->chocottoCampUserDetails($user['id'], true);
10972            
10973            $user['price_id'] = $chocottoPlanData['priceId'];
10974            $user['payment_plan_id'] = $chocottoPlanData['paymentPlanId'];
10975        
10976            // - update data 
10977            $data['ZPaymentFullLogs']['money'] = $chocottoPlanData['amount'];
10978            $data['paymentPlanData'] = $chocottoPlanData;
10979            $data['formType'] =  myTools::getChocottoPlanUserFormType($chocottoPlanData['paymentPlanId']);
10980        }
10981
10982        // NJ-32737
10983        $couponData = $this->Session->read('apply_coupon_usage_data');
10984
10985        if (!empty($couponData['useCouponAmount'])) {
10986            $data['couponUseSettlement'] = $couponData;
10987            $user['couponUseSettlement'] = $couponData;
10988        }
10989
10990        // process paypal settlement
10991        // redirect to charge page if return is false
10992        if ((isset($get['negativeTesting']) && $get['negativeTesting']) || !$this->processPayPalPayment($data, $user)) {
10993            $this->Session->setFlash('決済失敗', array("element" => "flashfail"));
10994
10995            $memKey = 'paypalBillingAgreementData_' . $get['token'];
10996
10997            // delete memcache billing agreement data
10998            if ($this->memcache->get($memKey)) {
10999                $this->memcache->delete($memKey);
11000            }
11001
11002            return $this->redirect(myTools::getUrl('payment/payment_credit_charge'));
11003        }
11004
11005        $memKey = 'creditChargePaymentGatewayType_' .$user['api_token'];
11006        // delete memcache payment gateway type
11007        if ($this->memcache->get($memKey)) {
11008            $this->memcache->delete($memKey);
11009        }
11010
11011        // delete session
11012        $this->Session->delete('paypalPaymentCreditChargeData');
11013
11014        // redirect to payment charge complete
11015        return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_charge_complete'));
11016    }
11017
11018    /**
11019     * @api {get} /:language/payment/payment_credit_retry payment_credit_retry()
11020     * @apiName payment_credit_retry
11021     * @apiGroup Payment
11022     * @apiDescription This endpoint is used to process payment credit retry.
11023     * 
11024     * @apiParam {String} language Language code of the user
11025     * 
11026     * @apiSuccess {View} Redirect redirects to zeus credit retry function for currency is equals to jpy
11027     * @apisuccess {View} Redirect redirects to wp credit retry function is non jpy
11028     * 
11029     * @apiSuccessExample Success Response JPY:
11030     * Redirects to zeus credit retry function
11031     * 
11032     * @apiSuccessExample Success Response Non JPY:
11033     * Redirects to wp credit retry function
11034     * 
11035     * @apiSampleRequest off
11036     */
11037    public function payment_credit_retry() {
11038        $this->response->disableCache();
11039        $this->blockWithdrawnSapuriToS();
11040        $this->disablePageForSapuri();
11041        $this->checkUser(Configure::read('payment_credit_retry'));
11042
11043        // NJ-68818: check if payment was charged after challenge already
11044        $this->checkIfChargedAfterChallenge($this->sharedUserData['User']['id'], 'retry');
11045
11046        // redirect to zeus if currency is equals to jpy
11047        if ($this->sharedUserData['User']['currency_code'] == Configure::read('default.user_currency')) {
11048            $this->zeus_credit_retry();
11049        // redirect to wp
11050        } else {
11051            $this->wp_credit_retry();
11052        }
11053
11054        $userData = $this->sharedUserData['User'];
11055        // NJ-30828: set view to display user's paypal email
11056        $this->setPaypalUser($userData);
11057    }
11058
11059    private function zeus_credit_retry() {
11060        $formType = Configure::read('payment_credit_retry');
11061        $logFileName = 'card_retry';
11062        $userData = $this->sharedUserData['User'];
11063
11064        // - reset sessions
11065        if ($this->Session->read('paypalPaymentCreditRetryData')){
11066            $this->Session->delete('paypalPaymentCreditRetryData');
11067        }
11068
11069        // - reset session
11070        if ($this->Session->read('credit_skip_to_confirmation')){
11071            $this->Session->delete('credit_skip_to_confirmation');
11072        }
11073
11074        $data = $this->Session->read('PaymentCreditRetryInfo');
11075        $this->set('data', $data);
11076
11077        // - NJ-18780: check if lite plan user 
11078        $isLitePlanUser = in_array($pData['paymentPlanId'], Configure::read('lite_payment_plans')) ? true : false;
11079
11080        
11081        
11082        // - check price id
11083        if (
11084            (!isset($userData['price_id']) || 
11085            empty($userData['price_id'])) & 
11086            $isLitePlanUser &&
11087            isset($userData['currency_code'])
11088        ) {
11089            $lightPlanData = $this->PaymentPlanPrice->getPaymentData(array(
11090                'currencyCode' => $userData['currency_code'],
11091                'paymentPlanId' => Configure::read('payment_plans.light_plan')
11092            ));
11093
11094            // if empty
11095            if (!$lightPlanData) {
11096                return $this->redirect(myTools::getUrl() . '/');
11097            }
11098            
11099            $userData['price_id'] = $lightPlanData['priceId'];
11100        }
11101
11102        // redirect to my page if empty payment plan data
11103        if (!$pData = $this->getRetryPaymentData($userData, $logFileName)) {
11104            return $this->redirect(myTools::getUrl() . '/');
11105        }
11106
11107        $userData['payment_plan_id'] = $pData['paymentPlanId'];
11108        $userData['price_id'] = $pData['priceId'];
11109        $userId = $userData['id'];
11110        $corporateId = $userData['corporate_id'];
11111        $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($userData['payment_plan_id']);
11112        $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userId);
11113        $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('appreciation_data.payment_element_type') );
11114        $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.live'));
11115        $discountedCoupon = 0;
11116
11117        // NJ-47740 - get monthly reqeust coupon discount
11118        $coupon = $this->UsersCouponV1->getCouponUseRequest(array(
11119            'userId' => $userId,
11120            'kbn' => Configure::read('coupon_kbn.monthly_settlement')
11121        ));
11122        
11123        if (!empty($coupon['amount']) && !empty($coupon['grp_id'])) {
11124            $userData['monthlyDiscount'] = $coupon['amount'];
11125            $userData['monthly_grp_id'] = $coupon['grp_id'];
11126            $discountedCoupon = $coupon['amount'];
11127        }
11128
11129        // get user active annual discount option
11130        $annualDiscountOptionData = $this->UserDiscountOptionsTerm->getTerm([
11131            'user_id' => $userData['id'],
11132            'discount_option_id' => Configure::read('discount_option.annual.plan_id'),
11133            'status' => 1
11134        ]);
11135        $annualDiscountOptionAmount = $annualDiscountOptionData ? $annualDiscountOptionData['amount'] : 0;
11136
11137        // check if post
11138        if ($this->request->is('post')) {
11139            $data = $this->request->data;
11140
11141            // redirect to paypal confirm page if payment gateway selected is paypal
11142            if ($data['payment_gateway_type'] == Configure::read('card_company.paypal')) {
11143                $data['paymentPlanData'] = $pData;
11144                $data['receivablePayment'] = $receivablePayment;
11145                $data['appreciationReceivable'] = $appreciationReceivable;
11146                $data['liveLessonReceivable'] = $liveLessonReceivable;
11147                $data['annualDiscountOptionAmount'] = $annualDiscountOptionAmount;
11148                
11149                //-new chocotto plan
11150                if ($pData['paymentPlanId'] == Configure::read('payment_plans.chocotto_plan')) {
11151                    $formType = Configure::read('payment_credit_chocotto_retry');
11152                }
11153                $data['formType'] = $formType;
11154
11155                if (isset($userData['monthlyDiscount']) && isset($userData['monthly_grp_id'])) {
11156                    $data['monthlyDiscount'] = $userData['monthlyDiscount'];
11157                    $data['monthly_grp_id'] = $userData['monthly_grp_id'];
11158                }
11159
11160                $this->Session->write('paypalPaymentCreditRetryData', $data);
11161                return $this->redirect(myTools::getUrl() . '/payment/paypal_payment_credit_retry_confirm');
11162            }
11163
11164            // delete payment gateway type memcache
11165            $this->memcache->delete('creditRetryPaymentGatewayType_' . $userData['api_token']);
11166
11167            $data['ZPaymentFullLogs']['clientip'] = Configure::read('ZEUS_clientip');
11168            $data['ZPaymentFullLogs']['telno'] = Configure::read('credit.default_telno');
11169
11170            if ($this->Session->read('PaymentCreditRetryInfo')) {
11171                $this->Session->delete('PaymentCreditRetryInfo');
11172            }
11173
11174            $this->Session->write('PaymentCreditRetryInfo', $data);
11175
11176            // NJ-25522: Skip confirm page if using 3D secure challenge
11177            $zeus3DSecureChallengeFlg = $this->memcache->get('zeus3DSecureChallengeFlg_' . $userData['id']);
11178
11179            if ($zeus3DSecureChallengeFlg) {
11180                $formType = Configure::read('payment_credit_retry');
11181                //-new chocotto plan
11182                if ($pData['paymentPlanId'] == Configure::read('payment_plans.chocotto_plan')) {
11183                    $formType = Configure::read('payment_credit_chocotto_retry');
11184                }
11185
11186                $referrer = array('controller' => 'Payment', 'action' => 'payment_credit_retry');
11187                $this->z_start($data, $formType, $referrer);
11188            } else {
11189                $this->Session->write('credit_skip_to_confirmation',true);
11190                return $this->redirect(myTools::getUrl() . '/payment/payment_credit_retry_confirm');
11191            }
11192        }
11193
11194        // clear previously set tokens and set new token
11195        $this->unsetToken();
11196        $token = md5(uniqid(rand(), true));
11197        $this->Session->write('Payment.token', $token);
11198
11199        $lessonFee = $basicFee = 0;
11200        $corporateUser = !empty($corporateId) && !empty($corporateType) ? true : false;
11201        $corpSessionKey = 'PaymentCreditRetryInfoCorporateAmount';
11202
11203        // delete corporate retry session if exist
11204        if ($this->Session->read($corpSessionKey)) {
11205            $this->Session->delete($corpSessionKey);
11206        }
11207
11208        // NJ-23812 : fetch the unformatted amount without tax
11209        $monthlyPriceRaw = 0;
11210
11211        // if corporate user
11212        if ($corporateUser) {
11213            $corporateTaxRate = Configure::read('tax.increase');
11214
11215            // if light
11216            if ($corporateType == Configure::read('corporate_type.light')) {
11217                $getCorpMemberReceivable = $this->CorporatePaymentMemberReceivable->memberReceivable(array('user_id' => $userId));
11218                $lessonFee = isset($getCorpMemberReceivable["lesson_fee"]) ? $getCorpMemberReceivable["lesson_fee"] : 0 ;
11219                $basicFee = isset($getCorpMemberReceivable["basic_fee"]) ? $getCorpMemberReceivable["basic_fee"] : 0 ;
11220                $amountWoTax = isset($getCorpMemberReceivable["basic_fee_wo_tax"]) ? $getCorpMemberReceivable["basic_fee_wo_tax"] : 0 ;
11221                $userData['lesson_fee'] = $lessonFee;
11222                $userData['basic_fee'] = $basicFee;
11223                $pData['amount'] = isset($getCorpMemberReceivable["total"]) ? $getCorpMemberReceivable["total"] : 0;
11224                $pData['fAmount'] = myTools::formatAmount($amountWoTax);
11225                $monthlyPriceRaw = $amountWoTax;
11226                $this->Session->write($corpSessionKey, $pData['fAmount']);
11227                $userData['corporateSettlementType'] = Configure::read('corporate_settlement_types.retry_payment');
11228            // if premium or standard
11229            } elseif (in_array($corporateType, array(Configure::read('corporate_type.premium'), Configure::read('corporate_type.standard')))) {
11230                $unpaidCPRParams = array(
11231                    'userId' => $userId,
11232                    'corporateId' => $corporateId,
11233                    'corporateType' => $corporateType
11234                );
11235
11236                // get unpaid corporate payment receivable
11237                $unpaidCPRData= $this->CorporatesPaymentReceivable->getIndiUnPaidReceivable($unpaidCPRParams);
11238
11239                // generate corporate payment receivable if no unpaid corporate payment receivable
11240                if (!$unpaidCPRData) {
11241                    $corpType = myTools::getCoporateTypeUsingPaymentPlanId($userData['payment_plan_id']);
11242                    $corpTypeStandard = Configure::read('corporate_type.standard');
11243                    $corpTypePremium = Configure::read('corporate_type.premium');
11244
11245                    $cprTypes = array(
11246                        Configure::read('corporate_type.standard') => $this->CorporatesPaymentReceivable->typeCorporateStandard,
11247                        Configure::read('corporate_type.premium') => $this->CorporatesPaymentReceivable->typeCorporatePremium
11248                    );
11249
11250                    // get payment plan data
11251                    $monthlyPaymentData = $this->PaymentPlanPrice->getPaymentData(array(
11252                        'currencyCode' => $userData['currency_code'],
11253                        'paymentPlanId' => $userData['payment_plan_id']
11254                    ));
11255
11256                    $cprDiscount = (int)$this->CorporateDiscountRate->getDiscount(array(
11257                        'corporateId' => $corporateId, 
11258                        'corporateType' => $corpType
11259                    ));
11260
11261                    $insertCPRData = array(
11262                        'corporate_id' => $corporateId,
11263                        'user_id' => $userId,
11264                        'type' => isset($cprTypes[$corpType]) ? $cprTypes[$corpType] : 0,
11265                        'status' => 0, // unpaid
11266                        'quantity' => 1,
11267                        'amount' => $monthlyPaymentData['amount'],
11268                        'discount' => $cprDiscount,
11269                        'next_settlement' => date('Y-m-d 00:00:00')
11270                    );
11271
11272                    $unpaidCPRData = array(
11273                        'amount' => $monthlyPaymentData['amount'],
11274                        'discount' => $cprDiscount
11275                    );
11276
11277                    // create corporate payment receivable
11278                    if (!$this->CorporatesPaymentReceivable->addReceivablePayment($insertCPRData)) {
11279                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to create payment receivable.', $data);
11280                        return ;
11281                    }
11282
11283                }
11284
11285                $cprAmountWoTax = $unpaidCPRData['amount'] - $unpaidCPRData['discount'];
11286                $monthlyPriceRaw = $cprAmountWoTax;
11287                $pData['amount'] = (int)$cprAmountWoTax * $corporateTaxRate;
11288                $pData['fAmount'] = myTools::formatAmount($cprAmountWoTax);
11289                $this->Session->write($corpSessionKey, $pData['fAmount']);
11290                $userData['updateCorporateReceivable'] = true;
11291                $userData['corporateSettlementType'] = Configure::read('corporate_settlement_types.retry_payment');
11292            }
11293        }
11294
11295        // add retry payment, receivable payment amount and live lesson payment 
11296        $userData['paymentAmount'] = $pData['amount'] + $receivablePayment + $appreciationReceivable + $liveLessonReceivable - $annualDiscountOptionAmount - $discountedCoupon;
11297        $userData = $this->changePaymentPlanIfTelecomUser($userData);
11298
11299        if ($annualDiscountOptionData) {
11300            unset($annualDiscountOptionData['contract_start']);
11301            $annualDiscountOptionData += [
11302                'dosh_event' => Configure::read('discount_option.dosh_event.annual_discount'),
11303                'dosh_status' => Configure::read('discount_option.dosh_status.monthly_discount')
11304            ];
11305            $userData['annualDiscountOption'] = $annualDiscountOptionData;
11306        }
11307
11308        //-new chocotto plan
11309        if ($pData['paymentPlanId'] == Configure::read('payment_plans.chocotto_plan')) {
11310            $formType = Configure::read('payment_credit_chocotto_retry');
11311        }
11312
11313        // set transaction error to 1 if failed to create payment transaction
11314        if (!$pt = $this->createPaymentTransaction($formType, $userData)) {
11315            $this->set('transactionError', 1);
11316        }
11317
11318        // NC-3914
11319        $this->getAndSetCardInfo($userData);
11320
11321        $currencyData = $this->Currency->getSymbolAndPosition($userData['currency_code']);
11322        $this->set('monthlyPrice', myTools::addPriceSymbol($pData['fAmount'], $currencyData['symbol'], $currencyData['prefix_suffix_flg']));
11323    
11324        //-new chocotto plan
11325        if ($pData['paymentPlanId'] == Configure::read('payment_plans.chocotto_plan')) {
11326            $formType = Configure::read('payment_credit_chocotto_retry');
11327        }
11328
11329        // ------  NJ-23812 : start support paypal skip confirmation page
11330        $sessionPaypalParams = array(
11331            'payment_gateway_type' => Configure::read('card_company.paypal'),
11332            'token' => $token,
11333            'ZPaymentFullLogs' => array(
11334                'paymentHash' => isset($paymentHash) ? $paymentHash : "" ,
11335                'money' => $pData['amount'],
11336                'discounted_amount' => (isset($userData['monthlyDiscount']) ? $userData['monthlyDiscount'] : 0),
11337                'monthlyDiscount' => (isset($userData['monthlyDiscount']) ? $userData['monthlyDiscount'] : 0)
11338            ),
11339            'paymentPlanData' => $pData,
11340            'receivablePayment' => $receivablePayment,
11341            'appreciationReceivable' => $appreciationReceivable,
11342            'liveLessonReceivable' => $liveLessonReceivable,
11343            'formType' => $formType
11344        );
11345
11346        if ($annualDiscountOptionData) {
11347            $sessionPaypalParams['annualDiscountOption'] = $annualDiscountOptionData;
11348        }
11349
11350        if (isset($userData['monthlyDiscount']) && isset($userData['monthly_grp_id'])) {
11351            $sessionPaypalParams['monthlyDiscount'] = $userData['monthlyDiscount'];
11352            $sessionPaypalParams['monthly_grp_id'] = $userData['monthly_grp_id'];
11353        }
11354
11355        $this->Session->write('paypalPaymentCreditRetryData', $sessionPaypalParams);
11356        $isZeusUser = isset($userData['card_company']) && $userData['card_company'] == 1 ? true : false;
11357
11358        // ------ End confirmation page ----------
11359
11360        $this->set('token', $token);
11361        $this->set('currencyData', $currencyData);
11362        $this->set('paypalUserData', $userData);
11363        $this->set('userApiToken', $userData['api_token']);
11364        $this->set('isZeusUser', $isZeusUser);
11365
11366        // - NJ-23812 : set view corp
11367        $this->set('monthlyPriceRaw',$monthlyPriceRaw);
11368        $this->set('currencySymbol',$currencyData['symbol']);
11369        $this->set('monthlyPriceSymbol',myTools::getCurrencySymbol($userData['currency_code']));
11370
11371
11372        $this->setSupportPayPal($userData);
11373        $this->set('zeusTransactionFlag', true);
11374        $this->set('paymentHash', $pt['payment_hash']);
11375        $this->set('amount', $pData['amount']);
11376        $this->set('fAmount', $pData['fAmount']);
11377        $this->set('lessonFee', $lessonFee);
11378        $this->set('basicFee', $basicFee);
11379        $this->set('discountedAmount', (isset($userData['discounted_amount']) ? $userData['discounted_amount'] : 0));
11380        $this->set('corporateFlg', $corporateUser);
11381        $this->set('corporateType', $corporateType);
11382        $this->setPaymentViewVars();
11383    }
11384
11385    private function wp_credit_retry() {
11386
11387        // - NJ-23812
11388        if ($this->Session->read('credit_skip_to_confirmation')) {
11389            $this->Session->delete('credit_skip_to_confirmation');
11390        }
11391
11392        // set variables
11393        $userData = $this->sharedUserData['User'];
11394        $apiToken = $userData['api_token'];
11395        $memKey = "pc_wp_retry_card_type_{$apiToken}";
11396        $memData = $this->memcache->get($memKey);
11397        $cardType = isset($memData['cardType']) ? $memData['cardType'] : 0;
11398
11399        // redirect to mypage if empty payment data and payment plan id or price id is null
11400        if (!$pData = $this->getRetryPaymentData($userData, 'card_retry')) {
11401            return $this->redirect('/');
11402        }
11403
11404        if ($this->request->is('post')) {
11405            $cardType = $this->request->data['cardType'];
11406
11407            // memcache card type value
11408            $this->memcacheCardType(array(
11409                'key' => $memKey,
11410                'value' => array('cardType' => $cardType)
11411            ));
11412
11413            // redirect to hosted page if using new card ($cardType = 1)
11414            if ($cardType) {
11415                return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/payment/wp_credit_retry_form");
11416            // redirect to confirm page if using existing card ($cardType = 0)
11417            } else {
11418
11419                // - NJ-23812: write session to skip and auto charge 
11420                $this->Session->write('credit_skip_to_confirmation',true);
11421
11422                return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/payment/payment_credit_retry_confirm");
11423            }
11424        }
11425
11426        /* check if there is error during payment process */
11427        if ($errorType = isset($this->request->query['wpErrType']) ? $this->request->query['wpErrType'] : null) {
11428            if ($error = myTools::getWorldpayErrorMsg($errorType)) {
11429                $this->set('error', $error);
11430            }
11431        } else {
11432            $memErrorKey = 'pc_wp_retry_error_' . $apiToken;
11433            if ($error = $this->memcache->get($memErrorKey)) {
11434                $this->set('error', $error);
11435
11436                // delete memcache error
11437                $this->memcache->delete($memErrorKey);
11438            }
11439        }
11440
11441        // -- start NJ-23812 : skip confirmation page  ------
11442        $formType = Configure::read('payment_credit_retry');
11443        $this->checkUser($formType);
11444
11445        // check if allowed aftee
11446        $this->checkAfteeSupported($this->sharedUserData['User'],true);
11447
11448        $isCardRegistered = (!empty($userData['card_brand']) && !empty($userData['card_number'])) ? true : false;
11449
11450        // - set view variables 
11451        $this->set('pmtValue', 'payment');
11452        $this->set('isCardRegistered',$isCardRegistered);
11453        $this->set('apiToken', $apiToken);
11454        $this->set('logFileName', 'payment_credit_retry');
11455        $this->set('nc_terminal_type', 1); // pc
11456        $this->set('memKeyError', 'pc_wp_retry_error_'.$apiToken);
11457        $this->set('referrer', urlencode(myTools::getUrl(). "/{$this->localizeDir}/payment/payment_credit_retry"));
11458        $this->set('successUrl', urlencode(myTools::getUrl()."/{$this->localizeDir}/payment/payment_credit_retry_complete"));
11459        $this->set('formType', $formType);
11460
11461        // -- end NJ-23812 ----------------------------------
11462
11463        $currencyData = $this->Currency->getSymbolAndPosition($userData['currency_code']);
11464        $this->set('monthlyPrice', $pData['fAmount']);
11465        $this->set('monthlyPriceSymbol',myTools::getCurrencySymbol($userData['currency_code']));
11466
11467        // set view variables
11468        $this->set('cardLogo', myTools::getWorldpayCardLogo($userData['card_brand']));
11469        $this->set('cardType', $cardType);
11470        $this->set('cardBrand', $userData['card_brand']);
11471        $this->set('cardNumber', $userData['card_number']);
11472        $this->render('/Payment/wp_payment_credit_retry');
11473    }
11474    /**
11475     * @api {get} /:language/payment/payment_credit_retry_confirm payment_credit_retry_confirm()
11476     * @apiName payment_credit_retry_confirm
11477     * @apiGroup Payment
11478     * @apiDescription This endpoint is used to process payment credit retry confirmation.
11479     * 
11480     * @apiParam {String} language Language code of the user
11481     * 
11482     * @apiSuccess {View} Redirect redirects to zeus credit retry confirm function for currency is equals to jpy
11483     * @apisuccess {View} Redirect redirects to wp credit retry confirm function is non jpy
11484     * 
11485     * @apiSuccessExample Success Response JPY:
11486     * Redirects to zeus credit retry confirm function
11487     * 
11488     * @apiSuccessExample Success Response Non JPY:
11489     * Redirects to wp credit retry confirm function
11490     * 
11491     * @apiSampleRequest off
11492     */
11493    public function payment_credit_retry_confirm() {
11494        $this->checkUser(Configure::read('payment_credit_retry'));
11495        // redirect to zeus if currency is equals to jpy
11496        if ($this->sharedUserData['User']['currency_code'] == Configure::read('default.user_currency')) {
11497            $this->zeus_credit_retry_confirm();
11498        // redirect to wp
11499        } else {
11500            $this->wp_credit_retry_confirm();
11501        }
11502    }
11503
11504    private function zeus_credit_retry_confirm() {
11505        $data = $this->Session->read('PaymentCreditRetryInfo');
11506        if (!$data) {
11507            return $this->redirect(myTools::getUrl() . '/');
11508        }
11509        $userData = $this->sharedUserData['User'];
11510        $corporateFlg = ( !empty($userData["corporate_id"]) && !empty($userData["payment_plan_id"]) );
11511
11512        $readSkipConfirmation = $this->Session->read('credit_skip_to_confirmation');
11513        if ($readSkipConfirmation) {
11514            $this->Session->delete('credit_skip_to_confirmation');
11515        }
11516
11517        if ($this->request->is('post') || $readSkipConfirmation) {
11518            # check if token matches token in session
11519            $checkToken = $this->checkToken($data['token']);
11520            # check if token is true
11521            if ($checkToken) {
11522                # unset previously set tokens
11523                $this->unsetToken();
11524                $formType = Configure::read('payment_credit_retry');
11525                $referrer = array('controller' => 'Payment', 'action' => 'payment_credit_retry');
11526                $this->z_start($data, $formType, $referrer);
11527            }
11528        }
11529
11530        if (isset($data['ZPaymentFullLogs']['cardnumber']) && !empty($data['ZPaymentFullLogs']['cardnumber'])) {
11531            $cardNumberArr = str_split($data['ZPaymentFullLogs']['cardnumber'], 4);
11532            $this->set('cardNumber', end($cardNumberArr));
11533        } else {
11534            $this->getAndSetCardInfo($this->sharedUserData['User']);
11535        }
11536
11537        $currencyData = $this->Currency->getSymbolAndPosition($userData['currency_code']);
11538        $this->set('currencyData', $currencyData);
11539
11540        $corporateAmount = $this->Session->read('PaymentCreditRetryInfoCorporateAmount') ? $this->Session->read('PaymentCreditRetryInfoCorporateAmount') : null;
11541        $this->set('corporateAmount', $corporateAmount);
11542        $this->set('data', $data);
11543        $this->set('corporateFlg', $corporateFlg);
11544        $this->set('corporateType', myTools::getCoporateTypeUsingPaymentPlanId($userData['payment_plan_id'])); 
11545    }
11546
11547    private function wp_credit_retry_confirm() {
11548        $this->response->disableCache();
11549        // set variables
11550        $logFileName = 'card_retry';
11551        $formType = Configure::read('payment_credit_retry');
11552        $userData = $this->sharedUserData['User'];
11553        $userId = $userData['id'];
11554        $currencyCode = $userData['currency_code'];
11555        $apiToken = $userData['api_token'];
11556
11557        $readSkipConfirmation = $this->Session->read('credit_skip_to_confirmation');
11558        if ($readSkipConfirmation){
11559            $this->Session->delete('credit_skip_to_confirmation');
11560        }
11561
11562        $memKey = "pc_wp_retry_card_type_{$apiToken}";
11563        // redirect to mypage if memcache card type is not set
11564        if (!$this->memcache->get($memKey)) {
11565            return $this->redirect('/');
11566        }
11567
11568        // redirect to retry page if empty payment data and payment plan id or price id is null
11569        if (!$pData = $this->getRetryPaymentData($userData, $logFileName)) {
11570            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed getRetryPaymentData --> ' . json_encode($userData), 'error');
11571            return $this->redirect('/');
11572        }
11573
11574        $apiToken = $userData['api_token'];
11575        $userData['payment_plan_id'] = $pData['paymentPlanId'];
11576        $userData['price_id'] = $pData['priceId'];
11577        $amount = $pData['amount'];
11578
11579        if ($this->request->is('post') || $readSkipConfirmation) {
11580
11581            // NJ-47740
11582            // confiscate pending request coupon for native and callan option
11583            // since student are failed settlement -> native and then callan options are already cancelled
11584            $this->UsersCouponV1->confiscateOptionDiscount(array('userId' => $userId));
11585            $coupon = $this->UsersCouponV1->getCouponUseRequest(array(
11586                'userId' => $userId,
11587                'kbn' => Configure::read('coupon_kbn.monthly_settlement')
11588            ));
11589            
11590            if (
11591                !empty($coupon['result']) && 
11592                !empty($coupon['grp_id']) && 
11593                !empty($coupon['amount']) && 
11594                empty($coupon['has_payment']) // exclude if coupon has payment
11595            ) {
11596                $amount -= $userData['discounted_amount'] = $coupon['amount'];
11597                $userData['monthlyDiscount'] = $coupon['amount'];
11598                $userData['monthly_grp_id'] = $coupon['grp_id'];
11599            }
11600            // NJ-47740 end
11601
11602            $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userId);
11603            $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('appreciation_data.payment_element_type') );
11604            $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.live'));
11605
11606            // add retry payment, receivable payment amount and live lesson payment 
11607            $totalAmount = $amount + $receivablePayment + $appreciationReceivable + $liveLessonReceivable;
11608            $orderCode = myTools::generateOrderCode($userId);
11609
11610            $paymentMethodType = myTools::getWPPaymentMethodType($userData['card_brand'], 'payment');
11611            $merchantCode = myTools::getWPMerchantCode($paymentMethodType);
11612            $paymentMethod = explode('_', $paymentMethodType);
11613            $paymentMethod = isset($paymentMethod[0]) ? $paymentMethod[0] : null;
11614            $currencyExponents = Configure::read('worldpay.currency_exponents');
11615            $exponent = $currencyExponents[$currencyCode];
11616
11617            // get total amount with checking currency exponent
11618            $totalAmountArr = myTools::wpGetAmount($exponent, $totalAmount);
11619            $ncAmount = $totalAmountArr['ncAmount'];
11620            $wpAmount = $totalAmountArr['wpAmount'];
11621
11622            $wpData = array(
11623                'cardToken' => $userData['card_token'],
11624                'merchantCode' => $merchantCode,
11625                'paymentHash' => $orderCode,
11626                'wpPaymentAmount' => $wpAmount
11627            );
11628
11629            // set payment amount
11630            $userData['paymentAmount'] = $ncAmount;
11631
11632            // create payment transaction
11633            if (!$pt = $this->createPaymentTransaction($formType, $userData, $wpData)) {
11634                $this->log(__METHOD__ .' Failed to save payment transaction. Params --> ' . json_encode($wpData), $logFileName);
11635                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to save payment transaction. Params --> ' . json_encode($wpData), 'error');
11636                return $this->redirect('/');
11637            }
11638
11639            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - After save payment transaction. Params --> ' . json_encode($wpData), 'error');
11640
11641            // if aftee payment
11642            if ($userData['card_company'] == Configure::read('card_company.aftee') ) {
11643
11644                // default result
11645                $checkRes = array(
11646                    'OrderCode' => $orderCode,
11647                    'authentication_token' => $userData['card_token'],
11648                    'response' => 'Aftee payment amount is zero',
11649                    'customer' => array(
11650                        'phone_number' =>  $userData['phone_number']
11651                    )
11652                );
11653                $receivableResult = json_encode($checkRes);
11654                $afteeTransactionIdentifier = $userData['aftee_transaction_identifier'];
11655
11656
11657                if ($userData['paymentAmount'] > 0) {
11658
11659                    if (!class_exists('AfteePaymentService')) {
11660                        App::uses('AfteePaymentService','Lib');
11661                    }
11662                    $afteeService = new AfteePaymentService();
11663                    $afteeChecksumData = array(
11664                        'shopItemId' => "AFTEE" . $formType,
11665                        'itemName' => 'CreditRetryUsingExistingCard',
11666                        'itemPrice' => $userData['paymentAmount'],
11667                        'itemCount' => 1,
11668                        'customerPhoneNumber' => $userData['phone_number'],
11669                        'customerEmail' => $userData['email'],
11670                        'shopTransactionNo' => $orderCode,
11671                        'userID' =>  $userData['id']
11672                    );
11673                    $checksum = $afteeService->generateChecksum($afteeChecksumData, false);
11674                    $afteeData = array(
11675                        'authentication_token' => $userData['card_token'],
11676                        'related_id' => $userData['aftee_transaction_identifier'],
11677                        'checksum' => $checksum['checksum'],
11678                        'shop_transaction_no' => $orderCode,
11679                        'transaction_options' => array(1)
11680                    );
11681            
11682                    $afteePaymentData = array_merge($afteeData, $checksum['settlementData']);
11683        
11684                    // aftee execute payment
11685                    $receivableResult = $afteeService->directPayment($afteePaymentData);
11686                    $checkRes = json_decode($receivableResult, true);
11687
11688
11689                    if ( isset($checkRes['object']) && $checkRes['object'] == 'transaction') {
11690                        $prPaymentSuccess = true;
11691                    } else if ( !array_key_exists("object", $checkRes) || (isset($checkRes['object']) && $checkRes['object'] == 'error')) {
11692                        $prPaymentSuccess = false;
11693                    }
11694
11695                    $afteeTransactionIdentifier = isset($checkRes['id']) && !empty($checkRes['id']) ? $checkRes['id'] : NULL;
11696                    if (isset($checkRes['related_transaction']) && !empty($checkRes['related_transaction'])) {
11697                        $afteeTransactionIdentifier = $checkRes['related_transaction'];
11698                    }
11699                    $orderCode = isset($checkRes['shop_transaction_no']) && !empty($checkRes['shop_transaction_no']) ? $checkRes['shop_transaction_no'] : NULL;
11700                    $checkRes['OrderCode'] = $orderCode;
11701                }
11702
11703                // process payment data
11704                if ($prPaymentSuccess || $userData['paymentAmount'] == 0) {
11705                    // set user model
11706                    $uModel = $this->User;
11707                    $dataSource = $uModel->getDataSource();
11708                    $dataSource->begin();
11709
11710                    $afteeParams = array(
11711                        'data' => $checkRes,
11712                        'ptData' => $pt,
11713                        'logFileName' => $logFileName,
11714                        'dataSource' => $dataSource,
11715                        'amount' => $userData['paymentAmount'],
11716                        'userData' => $userData,
11717                        'transactionIdentifier' => $afteeTransactionIdentifier,
11718                        'aftee' => 1
11719                    );
11720    
11721                    $this->processAfteePayment($afteeParams);
11722                }
11723
11724                // update payment transaction
11725                $updateData = array(
11726                    'id' => $pt['id'],
11727                    'fields' => array(
11728                        'status' => $prPaymentSuccess,
11729                        'response_text' => array('aftee_directPayment_response' => $receivableResult))
11730                );
11731
11732                // update payment transaction
11733                $this->PaymentTransaction->updateAfteePaymentTransaction($updateData);
11734
11735
11736                // redirect to payment_credit_charge with error display if direct payment response is not authorised
11737                if (!$prPaymentSuccess && $userData['paymentAmount'] > 0) {
11738                    if (!class_exists('myMemcached')) {
11739                        App::uses('myMemcached', 'Lib');
11740                    }
11741                    $memKeyError = 'pc_wp_retry_error_' . $apiToken;
11742                    $memerror = __('トランザクションを完了できません。 もう一度お試しください。');
11743                    $memcached = new myMemcached();
11744                    $memcached->set(array(
11745                        'key' => $memKeyError,
11746                        'value' => $memerror,
11747                        'expire' => 3600 // 1 hour
11748                    ));
11749                    return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/payment/payment_credit_retry");
11750                }
11751
11752            } else {
11753
11754                $wpData = array(
11755                    'merchantCode' => $merchantCode,
11756                    'orderCode' => $orderCode,
11757                    'description' => 'Credit Retry Using Existing Card',
11758                    'currencyCode' => $currencyCode,
11759                    'exponent' => $exponent,
11760                    'amount' => $wpAmount,
11761                    'cardToken' => $userData['card_token'],
11762                    'email' => $userData['email'],
11763                    'authenticatedShopperId' => $userId,
11764                    'xmlName' => 'direct_payment_with_token',
11765                    'shopperIpAddress' => $_SERVER["REMOTE_ADDR"],
11766                    'wpTransactionIdentifier' => $userData['wp_transaction_identifier'],
11767                    'paymentMethod' => $paymentMethod
11768                );
11769
11770                $result = wpPaymentService::directPayment($wpData);
11771
11772                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - directPayment result --> ' . json_encode($result), 'error');
11773
11774                $updateData = array(
11775                    'id' => $pt['id'],
11776                    'fields' => array('response_text' => array('directPayment_response' => $result)),
11777                    'logFileName' => $logFileName
11778                );
11779
11780                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - before updatePaymentTransaction result --> ' . json_encode($updateData), 'error');
11781                
11782                // update payment transaction direct response
11783                $this->updatePaymentTransaction($updateData);
11784
11785                // redirect to payment credit retry with error display if direct payment response is not authorised
11786                if (!myTools::checkIfWPPaymentResponseIsAuthorised($result)) {
11787                    $params = array(
11788                        'apiToken' => $apiToken,
11789                        'wpResponse' => $result,
11790                        'memKey' => 'pc_wp_retry_error_' . $apiToken
11791                    );
11792                    myTools::parseAndSetWPErrorResponse($params);
11793                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - WP Payment not authorised --> ' . json_encode($params), 'error');
11794                    return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/payment/payment_credit_retry");
11795                }
11796
11797                // - flag manual paying user success
11798                UserTable::saveManualPayingUsersToMemcache($userId);
11799            }
11800
11801
11802            // delete memcache
11803            if ($this->memcache->get($memKey)) {
11804                $this->memcache->delete($memKey);
11805            }
11806            return $this->redirect(myTools::getUrl() . "/{$this->localizeDir}/payment/payment_credit_retry_complete");
11807        }
11808
11809        $currencyData = $this->Currency->getSymbolAndPosition($currencyCode);
11810        $this->set('monthlyPrice', myTools::addPriceSymbol($pData['fAmount'], $currencyData['symbol'], $currencyData['prefix_suffix_flg']));
11811
11812        // set view variables
11813        $this->set('cardLogo', myTools::getWorldpayCardLogo($userData['card_brand']));
11814        $this->set('cardBrand', $userData['card_brand']);
11815        $this->set('cardNumber', $userData['card_number']);
11816        $this->set('cardCompany', $userData['card_company']);
11817        $this->render('/Payment/wp_payment_credit_retry_confirm');
11818    }
11819    /**
11820     * @api {get} /:language/payment/paypal_payment_credit_retry_confirm paypal_payment_credit_retry_confirm()
11821     * @apiName paypal_payment_credit_retry_confirm
11822     * @apiGroup Payment
11823     * @apiDescription This endpoint is used to display the paypal payment credit retry confirm form.
11824     * 
11825     * @apiParam {String} language Language code of the user
11826     * 
11827     * @apiSuccess {View} Render Displays the paypal payment credit retry confirm form
11828     * 
11829     * @apiError {View} Redirect Redirects to mypage if missing paypal payment credit retry data
11830     * 
11831     * @apiSuccessExample Success Response:
11832     * Displays the paypal payment credit retry confirm form
11833     * 
11834     * @apiErrorExample Error Response:
11835     * Redirects to mypage if missing paypal payment credit retry data
11836     * 
11837     * @apiSampleRequest off
11838     */
11839    public function paypal_payment_credit_retry_confirm() {
11840        $logFileName = 'paypal_debug';
11841        $user = $this->sharedUserData['User'];
11842
11843        $data = $this->Session->read('paypalPaymentCreditRetryData');
11844        if (!$data) {
11845            $this->log(__METHOD__ . ' Missing paypal payment credit retry data. --> ' . json_encode($data) . ' | user id  --> ' . json_encode($user['id']), $logFileName);
11846            return $this->redirect(myTools::getUrl());
11847        }
11848
11849        // set payment gateway type
11850        $this->memcache->set(array(
11851            'key' => 'creditRetryPaymentGatewayType_' . $user['api_token'],
11852            'value' => $data['payment_gateway_type'],
11853            'expire' => 3600 // 1 hour
11854        ));
11855
11856        $currencyData = $this->Currency->getSymbolAndPosition($user['currency_code']);
11857        $this->set('currencyData', $currencyData);
11858        $this->set('fAmount', myTools::formatAmount($data['ZPaymentFullLogs']['money']));
11859        $this->set('paypalUserData', $user);
11860        $this->set('userApiToken', $user['api_token']);
11861    }
11862    /**
11863     * @api {get} /:language/payment/wp_credit_retry_form wp_credit_retry_form()
11864     * @apiName wp_credit_retry_form
11865     * @apiGroup Payment
11866     * @apiDescription This endpoint is used to display the credit retry form for wp.
11867     * 
11868     * @apiParam {String} language Language code of the user
11869     * 
11870     * @apiSuccess {View} Render Displays the wp credit retry form
11871     * 
11872     * @apiError {View} Redirect Redirects to mypage if memcache card type is not set
11873     * 
11874     * @apiSuccessExample Success Response:
11875     * Displays the wp credit retry form
11876     * 
11877     * @apiErrorExample Error Response:
11878     * Redirects to mypage if memcache card type is not set
11879     * 
11880     * @apiSampleRequest off
11881     */
11882    public function wp_credit_retry_form() {
11883        $this->response->disableCache();
11884        $formType = Configure::read('payment_credit_retry');
11885        $this->checkUser($formType);
11886        $apiToken = $this->sharedUserData['User']['api_token'];
11887
11888        $memKey = "pc_wp_retry_card_type_{$apiToken}";
11889        // redirect to mypage if memcache card type is not set
11890        if (!$this->memcache->get($memKey)) {
11891            return $this->redirect('/');
11892        }
11893
11894        $enableAftee = (isset($this->localizeDir) && $this->localizeDir == 'zh-tw') ? 1 : 0;
11895        if (isset($this->sharedUserData['User']['currency_code']) && $this->sharedUserData['User']['currency_code'] != 'TWD') {
11896            $enableAftee = 0;
11897        }
11898        $this->set('enableAftee', false);
11899
11900        // set view vars
11901        $this->set('pmtValue', 'payment');
11902        $this->set('apiToken', $apiToken);
11903        $this->set('logFileName', 'payment_credit_retry');
11904        $this->set('nc_terminal_type', 1); // pc
11905        $this->set('memKeyError', 'pc_wp_retry_error_'.$apiToken);
11906        $this->set('referrer', urlencode(myTools::getUrl(). "/{$this->localizeDir}/payment/payment_credit_retry"));
11907        $this->set('successUrl', urlencode(myTools::getUrl()."/{$this->localizeDir}/payment/payment_credit_retry_complete"));
11908        $this->set('formType', $formType);
11909    }
11910    /**
11911     * @api {get} /:language/payment/paypal_payment_credit_retry_process/:token/:negativeTesting paypal_payment_credit_retry_process()
11912     * @apiName paypal_payment_credit_retry_process
11913     * @apiGroup Payment
11914     * @apiDescription This endpoint is used to process the paypal payment credit retry.
11915     * 
11916     * @apiParam {String} language Language code of the user
11917     * @apiParam {String} token Token of the user
11918     * @apiParam {Number} negativeTesting Negative testing flag 1 for true, 0 for false
11919     * 
11920     * @apiSuccess {View} Redirect Redirects to {{ENV}}/payment/payment_credit_retry_complete if payment is successful
11921     * 
11922     * @apiError {View} Redirect Redirects to {{ENV}}/payment/payment_credit_retry if payment is unsuccessful
11923     * 
11924     * @apiSuccessExample Success Response:
11925     * Redirects to {{ENV}}/payment/payment_credit_retry_complete
11926     * 
11927     * @apiErrorExample Error Response:
11928     * Redirects to {{ENV}}/payment/payment_credit_retry
11929     * 
11930     * @apiSampleRequest off
11931      */
11932    public function paypal_payment_credit_retry_process() {
11933        $this->autoRender = false;
11934        $this->layout = false;
11935
11936        $logFileName = 'paypal_debug';
11937        $user = $this->sharedUserData['User'];
11938        $userId = $user['id'];
11939        $get = $this->request->query;
11940
11941        $data = $this->Session->read('paypalPaymentCreditRetryData');
11942        $res = []; //NJ-69193 ~ Avoid Error as Fix
11943        if (!$data) {
11944            $this->log(__METHOD__ . ' Missing paypal payment credit retry data. --> ' . json_encode($data) . ' | user id  --> ' . json_encode($userId), $logFileName);
11945            return json_encode($res);
11946        }
11947
11948        if ((isset($get['negativeTesting']) && $get['negativeTesting']) || !$this->processPayPalPayment($data, $user)) {
11949            $this->Session->setFlash('決済失敗', array("element" => "flashfail"));
11950
11951            $memKey = 'paypalBillingAgreementData_' . $get['token'];
11952
11953            // delete memcache billing agreement data
11954            if ($this->memcache->get($memKey)) {
11955                $this->memcache->delete($memKey);
11956            }
11957
11958            return $this->redirect(myTools::getUrl('payment/payment_credit_retry'));
11959        }
11960
11961        $memKey = 'creditRetryPaymentGatewayType_' . $this->sharedUserData['User']['api_token'];
11962        // delete memcache
11963        if ($this->memcache->get($memKey)) {
11964            $this->memcache->delete($memKey);
11965        }
11966
11967        // delete session
11968        $this->Session->delete('paypalPaymentCreditRetryData');
11969
11970        // redirect to payment retry complete
11971        return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_retry_complete'));
11972    }
11973
11974    /**
11975     * @api {get} /payment/checkUser/:type/:referer/:return_membershiptype checkUser()
11976     * @apiName checkUser
11977     * @apiGroup Payment
11978     * @apiDescription This endpoint is used to check the user.
11979     * 
11980     * @apiParam {String} type Type of the user. Null by default
11981     * @apiParam {String} referer Referer of the user. Null by default
11982     * @apiParam {Boolean} return_membershiptype Return membership type of the user. False by default
11983     * 
11984     * @apiSuccess {String} memberType Returns the membership type of the user if return_membershiptype is true
11985     * @apiSuccess {View} Redirect Redirects to appropriate page
11986     * 
11987     * @apiSuccessExample Success Response Return Membership Type:
11988     * paid_user
11989     * 
11990     * @apiSuccessExample Success Response Redirect to Error Page:
11991     * Redirects to {{ENV}}/account/retry/error
11992     * 
11993     * @apiSuccessExample Success Response Redirect to Home Page:
11994     * Redirects to {{ENV}}/
11995     * 
11996     * @apiSuccessExample Success Response Redirect to Payment Credit Change Pass:
11997     * Redirects to {{ENV}}/payment/payment_credit_change
11998     * 
11999     * @apiSuccessExample Success Response Redirect to Payment Credit Register:
12000     * Redirects to {{ENV}}/payment/payment_credit_register
12001     * 
12002     * @apiSuccessExample Success Response Redirect to Payment Credit Retry:
12003     * Redirects to {{ENV}}/payment/payment_credit_retry
12004     * 
12005     * @apiSuccessExample Success Response Default:
12006     * true
12007     * 
12008     * @apiSampleRequest off
12009     */
12010    public function checkUser($type = null, $referer = null, $return_membershiptype = false) {
12011        $user = new UserTable($this->sharedUserData['User']);
12012        $memberType = $user->getUserMembership();
12013
12014        if($return_membershiptype) {
12015            return $memberType;
12016        }
12017
12018        // redirect to error page if settlement cron is currently on-going
12019        if (UserTable::checkPayingUser($user->id)) {
12020            return $this->redirect(myTools::getUrl() . '/account/retry/error');
12021        }
12022
12023        // NJ-25522: since payment has been made after 3D Secure challenge, membership of user is now updated
12024        // bypass membership checking; continue for cards without 3D Secure challenge
12025        $zeus3DSecureChallengeFlg = $this->memcache->get('zeus3DSecureChallengeFlg_' . $user->id);
12026        if ($zeus3DSecureChallengeFlg) {
12027            return true;
12028        }
12029
12030
12031        # if page is from retry
12032        if ($type == Configure::read('payment_credit_retry')) {
12033            if ($memberType == Configure::read('user.member_type_paid')) {
12034                return $this->redirect(myTools::getUrl() . '/');
12035            }
12036        }
12037
12038        # if page is from change
12039        if ($type == Configure::read('payment_credit_change')) {
12040            # get query
12041            $testQuery = $this->request->query;
12042            $currTime = (int) date("d");
12043
12044            # check test date now
12045            if (isset($testQuery["testDateNow"])) {
12046                $currTime = (int) date("d", strtotime($testQuery["testDateNow"]));
12047            }
12048
12049            # check if user is with telecom, and the current time is 1st day of month || time between 00:00:00 and 10:00:00
12050            if (
12051                $user->card_company == Configure::read("card_company.telecom")
12052                && $currTime === 1
12053            ) {
12054                # set the flash message
12055                # $this->Session->setFlash("Error : 本日は決済日のため、コイン購入およびカード情報変更を停止しております。 恐れ入りますが、手続きは明日以降にてお願い致します。", array("element" => "flashfail"));
12056                return $this->redirect(
12057                    array(
12058                        "controller" => "payment",
12059                        "action" => "payment_credit_change",
12060                        "?" => array(
12061                            "disabled" => 1
12062                        )
12063                    )
12064                );
12065            }
12066
12067            # if user is free
12068            if ($memberType == Configure::read('user.member_type_free')) {
12069                return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_register'));
12070            }
12071            # if user is a fail user
12072            if ($memberType == Configure::read('user.member_type_fail')) {
12073                return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_retry'));
12074            }
12075        }
12076
12077        # if page is from charge
12078        if ($type == Configure::read('payment_credit_force_charge')) {
12079            //NJ-3882 If User is Free (Trial not yet conducted)
12080            $membershipTypeIndex = $user->getMembershipTypeIndex();
12081            // allow corporate individual since it has no free trial
12082            if ($membershipTypeIndex == 13 && empty($user->corporate_id) && myTools::isDateEmpty($user->first_charge_date)) {
12083                return $this->redirect(myTools::getUrl() . '/');
12084            }
12085            
12086            if ($memberType == Configure::read('user.member_type_paid') && $user->payment_plan_id != Configure::read('payment_plans.complimentary_plan')) {
12087                return $this->redirect(myTools::getUrl() . '/');
12088            }
12089            // if user is free trial again, Corporate users has no free trial
12090            if ($memberType == Configure::read('user.member_type_free') && $user->double_check_flg == 1 && empty($user->corporate_id) && myTools::isDateEmpty($user->first_charge_date)) {
12091                return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_register'));
12092            }
12093
12094            // if failed user
12095            if ($memberType == Configure::read('user.member_type_fail')) {
12096                return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_retry'));
12097            }
12098        }
12099
12100        # if page is from register
12101        if ($type == Configure::read('payment_credit_authentication') && !$user->complimentary_code) {
12102            $membershipTypeIndex = $user->getMembershipTypeIndex();
12103            # if user is paid
12104            if ($memberType == Configure::read('user.member_type_paid')) {
12105                return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_change'));
12106            }
12107            # if user is a fail user
12108            if ($memberType == Configure::read('user.member_type_fail')) {
12109                return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_retry'));
12110            }
12111            # If user is free
12112            if ($membershipTypeIndex == 12) {
12113                return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_charge'));
12114            }
12115        }
12116
12117        # return true by default
12118        return true;
12119    }
12120
12121    /**
12122     * validate form data
12123     * @param  [type] $data [description]
12124     * @return status of form validity
12125     */
12126    public function formDataValidation($data) {
12127        $err = array();
12128        $year = (int)date('y');
12129        $valid = array('3','4','5','6');
12130        $form = 'ZPaymentFullLogs';
12131
12132        // NC-3914: if paymnent type is either retry | charge and user didn't use new card.
12133        if (isset($data[$form]['credit_confirm']) && !$data[$form]['credit_confirm']) {
12134            return array('err' => false);
12135        }
12136
12137        // NC-2961: return error false if zeus card option exist
12138        if (isset($data[$form]['zeus_card_option'])) {
12139            return array('err' => false);
12140        }
12141        
12142        if (!isset($data[$form]['clientip'])) {
12143            unset($data[$form]['clientip']);
12144            $err[] = $form."ClientIp";
12145        }
12146
12147        if (isset($data[$form]['cardnumber']) && preg_match("/[^0-9]/", $data[$form]['cardnumber']) != 1) {
12148            if ( (strlen($data[$form]['cardnumber']) >= 14 && strlen($data[$form]['cardnumber']) <= 16) == false || !in_array($data[$form]['cardnumber'][0], $valid) ) {
12149                unset($data[$form]['cardnumber']);
12150                $err[] = $form."Cardnumber";
12151            }
12152        }
12153
12154        if (isset($data[$form]['expyy']) && preg_match("/[^0-9]/", $data[$form]['expyy']) != 1 && !((int)$data[$form]['expyy'] >= $year && (int)$data[$form]['expyy'] <= $year+20)) {
12155            unset($data[$form]['expyy']);
12156            $err[] = $form."ExpirationDate";
12157        }
12158
12159        if (isset($data[$form]['expmm']) && preg_match("/[^0-9]/", $data[$form]['expmm']) != 1 && !((int)$data[$form]['expmm'] >= 1 && (int)$data[$form]['expmm'] <= 12)) {
12160            unset($data[$form]['expmm']);
12161            $err[] = $form."ExpirationDate";
12162        }
12163
12164        if (isset($data[$form]['username']) && preg_match("/^[a-zA-Z ]/", $data[$form]['username']) != 1 && $data[$form]['username']) {
12165            unset($data[$form]['username']);
12166            $err[] = $form."Username";
12167        }
12168
12169        if (isset($data[$form]['telno']) && preg_match("/[^0-9]/", $data[$form]['telno']) != 1 && strlen($data[$form]['telno']) < 10) {
12170            unset($data[$form]['telno']);
12171            $err[] = $form."Telno";
12172        }
12173
12174        if (count($err) == 0) {
12175            return array('err' => false);
12176        } else {
12177            return array('err' => $err, 'data' => $data);
12178        }
12179    }
12180
12181    /**
12182     * withdraw from telecom or zeus
12183     * @param  [type] $user_id [description]
12184     * @return [type]          [description]
12185     */
12186    public function withdraw($user_id = null) {
12187        $response = "NG";
12188
12189        // check if user id exists
12190        if (!$user_id) {
12191            return $response;
12192        }
12193
12194        // get user by id
12195        $user = $this->User->findById($user_id);
12196
12197        // check if user exists
12198        if (!$user) {
12199            return $response;
12200        }
12201
12202        // check card affiliation
12203        if ($user['User']['card_company'] != NULL) {
12204            if ($user['User']['card_company'] == Configure::read('card_company.telecom')) {
12205                    return "OK";
12206            } else if ($user['User']['card_company'] == Configure::read('card_company.zeus')) {
12207                $clientip = $user['User']['card_company'];
12208            }
12209        } else {
12210            return $response;
12211        }
12212
12213        // zpayment get succeeded
12214        $zpayment = $this->ZPaymentSucceeded->find('first',array(
12215                'recursive' => -1,
12216                'conditions' => array(
12217                        'ZPaymentSucceeded.user_id' => $user['User']['id'],
12218                        'ZPaymentSucceeded.clientip' => $clientip,
12219                        // 'ZPaymentSucceeded.created >=' => date('Y-m-d', strtotime('-1 month'.date('Y-m-d'))), //CONFIRM: add condition to select only transactions within the month?
12220                        'LOWER(ZPaymentSucceeded.result)' => "ok"
12221                    ),
12222                'order' => array('ZPaymentSucceeded.created' => 'DESC')
12223            )
12224        );
12225
12226        // check if user has zpayment
12227        if (!$zpayment) {
12228            $data['user_id'] = $user['User']['id'];
12229            $data['error_code'] = Configure::read('zeus.error.no_transaction_record');
12230            $this->_error_log_set($data);
12231            echo "No Transaction Record";
12232            return $response;
12233        }
12234
12235        // withdraw ang get the result
12236        $result = $this->ZCharge->cancel(
12237            $clientip,
12238            $zpayment['ZPaymentSucceeded']['ordd']
12239        );
12240
12241        // check if result is false
12242        if ($result === FALSE) {
12243            echo "Invalid Withdrawal";
12244            exit;
12245        }
12246
12247        if (preg_match('/SuccessOK/', $result) == 1) {
12248            return $response = "OK";
12249        } else if (preg_match('/failure_order/', $result) == 1) {
12250            return $response;
12251        } else if (preg_match('/Invalid/', $result) == 1) {
12252            return $response;
12253        } else if (preg_match('/maintenance/', $result) == 1) {
12254            return $response;
12255        } else if (preg_match('/connect error/', $result) == 1) {
12256            return $response;
12257        }
12258    }
12259
12260    /**
12261     * @api {post} /payment/withdraw_confirm withdraw_confirm()
12262     * @apiName withdraw_confirm
12263     * @apiGroup Payment
12264     * @apiDescription This endpoint is used to confirm the withdrawal.
12265     * 
12266     * @apiBody {Number} card_company Card company of the user
12267     * 
12268     * @apiSuccess {PHP} Set sets the selected card company, current card company, user id and referer for view
12269     * 
12270     * @apiError {View} Redirect Redirects to payment_credit_change if request is not post
12271     * 
12272     * @apiExample {json} Example usage:
12273     * {
12274     *         "card_company": 1
12275     * }
12276     * @apiSuccessExample Success Response:
12277     * Sets the selected card company, current card company, user id and referer for view
12278     * 
12279     * @apiErrorExample Error Response:
12280     * Redirects to payment_credit_change if request is not post
12281     * 
12282     * @apiSampleRequest off
12283     */
12284    public function withdraw_confirm() {
12285        $this->checkUser(Configure::read('payment_credit_change'));
12286        if ($this->request->is('post')) {
12287            $data = $this->request->data;
12288            $user = $this->User->findById($this->Auth->user('id'));
12289            $this->set('selected_card_company', $data['card_company']);
12290            $this->set('current_card_company', $user['User']['card_company']);
12291            $this->set('user_id', $user['User']['id']);
12292            $this->set('referer', $this->referer());
12293        } else {
12294            return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_change'));
12295        }
12296    }
12297
12298    /**
12299     * @api {get} /payment/checkToken/:token checkToken()
12300     * @apiName checkToken
12301     * @apiGroup Payment
12302     * @apiDescription This endpoint is used to check the token.
12303     * 
12304     * @apiParam {String} token Token of the user
12305     * 
12306     * @apiSuccess {Boolean} true returns true if token is valid
12307     * 
12308     * @apiError {View} Redirect Redirects to mypage if token is invalid
12309     * 
12310     * @apiSuccessExample Success Response:
12311     * true
12312     * 
12313     * @apiErrorExample Error Response:
12314     * Redirects to mypage if token is invalid
12315     * 
12316     * @apiSampleRequest off
12317     */
12318    public function checkToken($token = null){
12319        //get session token
12320        $sessionToken = isset($_SESSION['Payment']['token']) ? $_SESSION['Payment']['token'] : '';
12321
12322        if ($token == $sessionToken) {
12323            return true;
12324        } else {
12325            $this->redirect(myTools::getUrl() . '/');
12326        }
12327    }
12328
12329    /**
12330     * @api {post} /payment/unsetToken unsetToken()
12331     * @apiName unsetToken
12332     * @apiGroup Payment
12333     * @apiDescription This endpoint is used to unset the token.
12334     * 
12335     * @apiSuccess {PHP} unset unsets the token
12336     *
12337     * @apiSuccessExample Success Response:
12338     * unsets the token
12339     * 
12340     * @apiSampleRequest off 
12341     */
12342    public function unsetToken() {
12343        if (isset($_SESSION['Payment']['token'])) {
12344            unset($_SESSION['Payment']['token']);
12345        }
12346        return;
12347    }
12348
12349    /**
12350     * Create payment transaction
12351     */
12352    private function createPaymentTransaction($formType = null, $userData = array(), $wpData = array()) {
12353        $pt = array();
12354
12355        if (!$userData) {
12356            $userData = isset($this->sharedUserData['User']) ? $this->sharedUserData['User'] : null;
12357            if (!$userData) {
12358                return $pt;
12359            }
12360        }
12361
12362        if (!$formType) {
12363            return $pt;
12364        }
12365
12366        switch ($formType) {
12367            case Configure::read('payment_credit_retry'):
12368            case Configure::read('payment_credit_chocotto_retry'):
12369                $logFileName = 'card_retry';
12370                break;
12371            case Configure::read('payment_credit_authentication'):
12372            case Configure::read('payment_lite_credit_free'):
12373            case Configure::read('payment_credit_chocotto_free'):
12374                $logFileName = 'card_registration';
12375                break;
12376            case Configure::read('corporate_credit_card_registration'):
12377                $logFileName = 'corporate_credit_card_registration';
12378                break;
12379            case Configure::read('payment_credit_force_charge'):
12380            case Configure::read('payment_prepaid_corporate_light_member'):
12381            case Configure::read('payment_individual_corporate_premium'):
12382            case Configure::read('payment_individual_corporate_standard'):
12383            case Configure::read('payment_lite_credit_paid'):
12384            case Configure::read('payment_credit_chocotto_force_charge'):
12385                $logFileName = 'card_charge';
12386                break;
12387            case Configure::read('payment_credit_change'):
12388                $logFileName = 'card_change';
12389                break;
12390            default:
12391                $logFileName = 'debug';
12392        }
12393
12394        $corporateUser = (isset($userData['corporate_id']) && !empty($userData['corporate_id']));
12395        if (!$corporateUser) {
12396            if (!isset($userData['payment_plan_id'])) {
12397                $this->log(__METHOD__ . ' missing parameter payment plan id. ' . json_encode($userData), $logFileName);
12398                return $pt;
12399            }
12400
12401            if (!isset($userData['price_id'])) {
12402                $this->log(__METHOD__ . ' missing parameter price id. ' . json_encode($userData), $logFileName);
12403                return $pt;
12404            }
12405        }
12406
12407        // change form type if corporate user
12408        if ($corporateUser && $formType == Configure::read('payment_credit_retry')) {
12409            $corpType = myTools::getCoporateTypeUsingPaymentPlanId($userData['payment_plan_id']);
12410            // light
12411            if ($corpType == Configure::read('corporate_type.light')) {
12412                $formType = Configure::read('payment_prepaid_corporate_light_member');
12413            // premium
12414            } elseif ($corpType == Configure::read('corporate_type.premium')) {
12415                $formType = Configure::read('payment_individual_corporate_premium');
12416            // standard
12417            } elseif ($corpType == Configure::read('corporate_type.standard')) {
12418                $formType = Configure::read('payment_individual_corporate_standard');
12419            }
12420        }
12421
12422        // change form type if lite plan user
12423        $litePlanUser = (in_array($userData['payment_plan_id'], Configure::read('lite_payment_plans'))) ? true : false;
12424
12425        if (
12426            $litePlanUser &&
12427            !in_array($formType, array(Configure::read('payment_credit_change'),Configure::read('payment_credit_retry') ) ) &&
12428            !isset($userData['discountOption'])
12429        ) {
12430            $formType = myTools::getLitePlanUserFormType($userData['payment_plan_id']);
12431        }
12432
12433        // change form type if chocotto plan user
12434        $chocottoPlanUser = in_array(
12435            $userData['payment_plan_id'], 
12436            [
12437                Configure::read('payment_plans.free_trial_chocotto'),
12438                Configure::read('payment_plans.chocotto_plan')
12439            ]
12440        );
12441
12442        if (
12443            $chocottoPlanUser &&
12444            !in_array(
12445                $formType,
12446                array(
12447                    Configure::read('payment_credit_chocotto_retry'),
12448                    Configure::read('payment_credit_chocotto_force_charge'),
12449                    Configure::read('payment_credit_change')
12450                )
12451            )
12452        ) {
12453            $formType = myTools::getChocottoPlanUserFormType($userData['payment_plan_id']);
12454        }
12455
12456        // get payment hash
12457        $paymentHash = myTools::generateOrderCode($userData['id']);
12458
12459        // set payment params
12460        $paymentParams = array(
12461            'currencyCode' => $userData['currency_code'],
12462            'paymentPlanId' => $userData['payment_plan_id'],
12463            'priceId' => $userData['price_id'],
12464            'remoteAddress' => $_SERVER["REMOTE_ADDR"],
12465            'formType' => $formType,
12466            'paymentType' => Configure::read('payment_types.payment_plan'),
12467            'paymentAmount' => $userData['paymentAmount'],
12468            'logFileName' => $logFileName
12469        );
12470
12471        if (isset($userData['discountOption'])) {
12472            $paymentParams['discountOption'] = $userData['discountOption'];
12473
12474            if (isset($userData['userRegister'])) {
12475                $paymentParams['userRegister'] = $userData['userRegister'];
12476            }
12477        }
12478
12479        // if corporate user
12480        if ($corporateUser) {
12481            if (isset($userData['basic_fee']) && isset($userData['lesson_fee'])) {
12482                $paymentParams["basicFee"] = $userData['basic_fee'];
12483                $paymentParams["lessonFee"] = $userData['lesson_fee'];
12484            }
12485
12486            if (isset($userData['cprAmount']) && isset($userData['cprDiscount'])) {
12487                $paymentParams['addCorporateReceivable'] = array(
12488                    'amount' => $userData['cprAmount'],
12489                    'discount' => $userData['cprDiscount']
12490                );
12491            }
12492
12493            if (isset($userData['updateCorporateReceivable'])) {
12494                $paymentParams["updateCorporateReceivable"] = $userData['updateCorporateReceivable'];
12495            }
12496
12497            if (isset($userData['corporateSettlementType'])) {
12498                $paymentParams["corporateSettlementType"] = $userData['corporateSettlementType'];
12499            }
12500        }
12501
12502        // annual discount option
12503        if (isset($userData['annualDiscountOption'])) {
12504            $paymentParams['discountOption'] = $userData['annualDiscountOption'];
12505        }
12506
12507        // if worldpay payment transaction
12508        if ($wpData) {
12509            $paymentParams['cardToken'] = $wpData['cardToken'];
12510            $paymentParams['merchantCode'] = $wpData['merchantCode'];
12511            $paymentParams['wpPaymentAmount'] = $wpData['wpPaymentAmount'];
12512            $paymentHash = $wpData['paymentHash'];
12513        }
12514
12515        // set updateFirstChargeDate to true if current plan is complimentary
12516        // set memcache
12517        if (
12518            $formType == Configure::read('payment_credit_force_charge') &&
12519            isset($userData['com_plan_user']) && $userData['com_plan_user']
12520        ) {
12521            $paymentParams['updateFirstChargeDate'] = true;
12522            $this->memcache->set(array(
12523                'key' => 'com_plan_user_' . $userData['id'],
12524                'value' => true,
12525                'expire' => 3600 // 1 hour
12526            ));
12527        }
12528
12529        //- get membership type list
12530        $membershipTypes = UserTable::getEngMembershipTypeData();
12531
12532        //- check original membership is pass
12533        if (isset($userData['original_status_index'])) {
12534            $statusBefore = $membershipTypes[$userData['original_status_index']] ?? '';
12535        }
12536
12537        if (
12538            $formType != Configure::read('payment_credit_change') ||
12539            (isset($userData['com_plan_user']) && $userData['com_plan_user'])
12540        ) {
12541            $statusAfter = $membershipTypes[1]; // premium plan paid
12542
12543            /* -- get before status -- */
12544            if (isset($userData['com_plan_user']) && $userData['payment_plan_id'] == Configure::read('payment_plans.complimentary_plan')) {
12545                $statusBefore = $membershipTypes[15]; // complimentary code
12546                $paymentParams['bonusCoinFlg'] = 1;
12547            } elseif ($userData['charge_flg'] == 0) {
12548                // failed settlement
12549                if ($userData['fail_flg'] == 1) {
12550                    $statusBefore = $membershipTypes[5];
12551                // trial again
12552                } elseif ($userData['fail_flg'] == 0 && $userData['double_check_flg'] == 1) {
12553                    $statusBefore = $membershipTypes[13];
12554                    $statusAfter = $membershipTypes[2];
12555                // unsubscribed
12556                } elseif ($userData['fail_flg'] == 0 && $userData['double_check_flg'] == 2) {
12557                    $statusBefore = $membershipTypes[12];
12558                } else {
12559                    $statusBefore = null;
12560                }
12561            }
12562
12563            if ($corporateUser && $formType != Configure::read('payment_credit_force_charge')) {
12564                $statusAfter = myTools::getCorporateUserMembershipStatusName($membershipTypes, $userData['payment_plan_id']);
12565            }
12566
12567            $user = new UserTable($userData);
12568            $membershipTypeIndex = $user->getMembershipTypeIndex();
12569            if ($membershipTypeIndex == 13) {
12570                $statusBefore = $membershipTypes[13];
12571                $paymentParams['userRegister'] = true;
12572                $statusAfter = $membershipTypes[2];
12573            }
12574            
12575            if (isset($statusBefore)) {
12576                // get platform use
12577                $platform = myTools::mobappDetectPlatform();
12578                $paymentParams['platform'] = $platform == Configure::read('platform.splp') ? Configure::read('platform.pclp') : $platform;
12579                $paymentParams['statusBefore'] = $statusBefore;
12580                $paymentParams['statusAfter'] = $statusAfter;        
12581            } else if (isset($userData['statusBefore']) && isset($userData['statusAfter'])) {
12582                // get platform use
12583                $platform = myTools::mobappDetectPlatform();
12584                $paymentParams['platform'] = $platform == Configure::read('platform.splp') ? Configure::read('platform.pclp') : $platform;
12585                $paymentParams['statusBefore'] = $userData['statusBefore'];
12586                $paymentParams['statusAfter'] = $userData['statusAfter'];
12587            }
12588
12589            if ($litePlanUser) {
12590                $_lightPlanFreeMem = Configure::read('membership_type_lightplan_free');
12591                $_lightPlanPaidMem = Configure::read('membership_type_lightplan_paid');
12592                $paymentParams['statusAfter'] = ($formType == Configure::read('payment_lite_credit_free') ) ? $membershipTypes[$_lightPlanFreeMem] : $membershipTypes[$_lightPlanPaidMem];
12593            }
12594
12595            //- status after chocotto camp
12596            if (in_array($formType, [
12597                Configure::read('payment_credit_chocotto_free'),
12598                Configure::read('payment_credit_chocotto_monthly_payment'),
12599                Configure::read('payment_credit_chocotto_retry'),
12600                Configure::read('payment_credit_chocotto_force_charge')
12601            ])) {
12602                if ($formType == Configure::read('payment_credit_chocotto_free')) {
12603                    $paymentParams['statusAfter'] = $membershipTypes[Configure::read('membership_type_chocotto_plan_free')];
12604                } elseif (in_array(
12605                    $formType, 
12606                    array(
12607                        Configure::read('payment_credit_chocotto_monthly_payment'),
12608                        Configure::read('payment_credit_chocotto_retry'),
12609                        Configure::read('payment_credit_chocotto_force_charge')
12610                    )
12611                )) {
12612                    $paymentParams['statusAfter'] = $membershipTypes[Configure::read('membership_type_chocotto_plan_paid')];
12613                }
12614
12615                $prevPaymentPlanId = (isset($this->mobAppUserData) && !empty($this->mobAppUserData)) ?
12616                    $this->mobAppUserData['User']['payment_plan_id'] :
12617                    ((isset($this->sharedUserData) && $this->sharedUserData) ? $this->sharedUserData['User']['payment_plan_id'] : null);
12618                    
12619                if($prevPaymentPlanId == Configure::read('payment_plans.complimentary_plan')) {
12620                    if(!isset($statusBefore)) {
12621                        $paymentParams['statusBefore'] = $membershipTypes[15];
12622                    }
12623                    if(!isset($platform)) {
12624                        $platform = myTools::mobappDetectPlatform();
12625                        $paymentParams['platform'] = $platform == Configure::read('platform.splp') ? Configure::read('platform.pclp') : $platform;
12626                    }
12627                }
12628            }
12629        }
12630
12631        if (isset($userData['monthlyDiscount']) && isset($userData['monthly_grp_id'])) {
12632            $paymentParams['monthlyDiscount'] = $userData['monthlyDiscount'];
12633            $paymentParams['monthly_grp_id'] = $userData['monthly_grp_id'];
12634        }
12635
12636        if (!empty($userData['couponUseSettlement'])) {
12637            $this->log("LINE ". __LINE__,'card_charge');
12638            $this->log($userData['couponUseSettlement'],'card_charge');
12639            $paymentParams['couponUseSettlement'] = $userData['couponUseSettlement'];
12640        }
12641        //NJ-3882 set UserRegister = true for Free (Trial not yet conducted) user to add 500 bonus coin
12642        $user = new UserTable($userData);
12643        $membershipTypeIndex = $user->getMembershipTypeIndex();
12644
12645        if ($membershipTypeIndex == 13) {
12646            $paymentParams['userRegister'] = true;
12647        }
12648
12649        // - set data
12650        $test = $this->memcache->set(array(
12651            'key' => 'zeus_sec_payment_hash_'.$userData['id'],
12652            'value' => $paymentHash,
12653            'expire' => 600 // 10 minutes
12654        ));
12655
12656
12657        // create payment transaction
12658        $pt = $this->PaymentTransaction->setWPPaymentTransaction(array(
12659            'user_id' => $userData['id'],
12660            'payment_hash' => $paymentHash,
12661            'payment_params' => json_encode($paymentParams),
12662            'course_id' => Configure::read("credit.course_id")
12663        ));
12664
12665        return $pt;
12666    }
12667
12668    /**
12669     * @api {get} /payment/getPaymentTransaction/:userId getPaymentTransaction()
12670     * @apiName getPaymentTransaction
12671     * @apiGroup Payment
12672     * @apiDescription This endpoint is used to get payment transaction.
12673     * 
12674     * @apiParam {String} userId User's ID
12675     * 
12676     * @apiSuccess {PHP} return Returns the payment transation's payment hash
12677     * 
12678     * @apiError {Boolean} false Returns false if no data returned
12679     * 
12680     * @apiSuccessExample Success Response:
12681     * Returns the payment transation's payment hash
12682     * 
12683     * @apiErrorExample Error Response:
12684     * Returns false if no data returned
12685     * 
12686     * @apiSampleRequest off
12687     */
12688    public function getPaymentTransaction($userId = null) {
12689        $data = $this->PaymentTransaction->getPaymentTransaction($userId);
12690        if ($data) {
12691            return isset($data['payment_hash'])? $data['payment_hash'] : null;
12692        }
12693        return false;
12694    }
12695    /**
12696     * @api {get} /mobapp/payment/credit_register_receivable/:token mobapp_payment_credit_register_receivable()
12697     * @apiName mobapp_payment_credit_register_receivable
12698     * @apiGroup Payment
12699     * @apiDescription This endpoint is used to display credit register receivable page in mobapp.
12700     * 
12701     * @apiParam {String} token user's API token.
12702     * 
12703     * @apiSuccess {View} Render Displays the credit register receivable page.
12704     * 
12705     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage for token is missing / not set.
12706     * @apiError {String} Error Throws error exception if memcache does not exist or expired.
12707     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if not a light plan user
12708     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if user is not subscribed to the zero discount option
12709     * 
12710     * @apiSuccessExample Success Response:
12711     * Displays the credit register receivable page.
12712     * 
12713     * @apiErrorExample Error Response Missing token / not set:
12714     * Redirects to {{ENV}}/mobapp/retrypage
12715     * 
12716     * @apiErrorExample Error Response Not a light plan user:
12717     * Redirects to {{ENV}}/mobapp/retrypage
12718     * 
12719     * @apiErrorExample Error Response memchache does not exist or expired.
12720     * Throws NotFoundException error
12721     * 
12722     * @apiErrorExample Error Response not subscribed to the zero discount option:
12723     * Redirects to {{ENv}}/mobapp/retrypage
12724     * 
12725     * @apiSampleRequest off
12726     */
12727    public function mobapp_payment_credit_register_receivable() {
12728        $retryPageUrl = myTools::getUrl() . '/mobapp/retrypage' . myTools::getMobappToken($_GET); 
12729
12730        // redirect to retry page if param token is not set
12731        if (!isset($this->request->query['token'])) {
12732            return $this->redirect($retryPageUrl);
12733        }
12734
12735        $userToken = $this->request->query['token'];
12736        $userData = $this->User->findByApiToken($userToken);
12737
12738        // redirect to retry page if token does not exist
12739        if (!$userData) {
12740            return $this->redirect($retryPageUrl);
12741        }
12742
12743        $user = $userData['User'];
12744
12745        // throw error exception if memcache does not exist or expired
12746        if (!$memcache_receivable_data = $this->memcache->get('memcache_receivable_data' . $user['id'])) {
12747            throw new NotFoundException();
12748        }
12749
12750        $zeusMaintenance = false;
12751        if (myTools::zeusMaintenancePeriod()){
12752            $zeusMaintenance = true;
12753        }
12754
12755        $isCardRegistered = false;
12756        if ((!empty($user['card_brand']) && !empty($user['card_number']))) {
12757            $isCardRegistered = true;
12758        }
12759
12760        $userObj = new UserTable($user);
12761        $membershipType = $userObj->getMembershipTypeIndex();
12762
12763        // redirect to retry page if not light plan
12764        if (!in_array($membershipType, Configure::read('membership_type_lightplan'))) {
12765            return $this->redirect($retryPageUrl);
12766        }
12767
12768        // get user active zero student discount option data
12769        $zeroStudentDiscountOptionTermData = $this->UserDiscountOptionsTerm->getTerm([
12770            'user_id' => $userObj->id,
12771            'discount_option_id' => Configure::read('discount_option.zero_student.plan_id'),
12772            'status' => 1
12773        ]);
12774
12775        // redirect to retry page if not zero discount option user
12776        if (!$zeroStudentDiscountOptionTermData) {
12777            return $this->redirect($retryPageUrl);
12778        }
12779
12780        $this->getAndSetCardInfo($user);
12781        $this->set('zeroStudentDiscountOptionUser', true);
12782        $this->set('zeus_maintenance', $zeusMaintenance);
12783        $this->set('isCardRegistered', $isCardRegistered);
12784        $this->set('zeusTransactionFlag', true);
12785        $this->set('amount', 0);
12786        $this->set('discountedAmount', 0);
12787        $this->request->query['renderPath'] = myTools::getDeviceUrl() . 'Payment/payment_credit_register_receivable';
12788
12789        $this->mobapp_credit_change();
12790    }
12791
12792    /**
12793     * @api {get} /mobapp/payment/credit_change/:token/:unli_option/:page_origin/:renderPath mobapp_credit_change()
12794     * @apiName mobapp_credit_change
12795     * @apiGroup Payment
12796     * @apiDescription This endpoint is used to change user's credit card information.
12797     * 
12798     * @apiParam {String} token User's API token
12799     * @apiParam {String} unli_option User's unli option. Blank if not provided
12800     * @apiParam {String} page_origin User's page origin. Null if not provided
12801     * @apiParam {String} renderPath User's render path. Null if not provided
12802     * 
12803     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/credit_change_form
12804     * 
12805     * @apiError {View} Redirect Redirects to {{ENV}}//mobapp/payment/wp_credit_change for non-JPY currency users
12806     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/payment/failure_family for family plan users
12807     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/payment/credit_retry for free users and non-corporate individual users
12808     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage for token is missing
12809     * 
12810     * @apiSuccessExample Success Response:
12811     * Redirects to {{ENV}}/mobapp/payment/credit_change_form
12812     * 
12813     * @apiErrorExample Error Response (Non-JPY Currency):
12814     * Redirects to {{ENV}}/mobapp/payment/wp_credit_change
12815     * 
12816     * @apiErrorExample Error Response (Family Plan):
12817     * Redirects to {{ENV}}/mobapp/payment/failure_family
12818     * 
12819     * @apiErrorExample Error Response (Free User):
12820     * Redirects to {{ENV}}/mobapp/payment/credit_retry
12821     * 
12822     * @apiErrorExample Error Response (Token Missing):
12823     * Redirects to {{ENV}}/mobapp/retrypage
12824     * 
12825     * @apiSampleRequest off
12826     */
12827    public function mobapp_credit_change() {
12828        $this->blockWithdrawnSapuriToS('mobapp');
12829        $this->disablePageForSapuri('mobapp');
12830        // set variables
12831        $this->layout = "mobapp";
12832        $urlParams = myTools::getMobappToken($_GET);
12833        $logFileName = 'card_change';
12834        $formType = Configure::read('payment_credit_change');
12835        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType)); // get user data and validate
12836        $amount = $userData['PaymentPlanPrice']['amount'];
12837        $userData = $userData['User'];
12838        $apiToken = $this->request->query['token'];
12839        $fromUnliOption = isset($this->request->query['unli_option']) ? $this->request->query['unli_option'] : '';
12840        $urlRedirect = isset($this->request->query['page_origin']) ? $this->request->query['page_origin'] : null ;
12841        $renderPath = isset($this->request->query['renderPath']) ? $this->request->query['renderPath'] : null;
12842
12843        $userObj = new UserTable($userData);
12844        $membershipTypeIndex = $userObj->getMembershipTypeIndex();
12845        if(
12846            $membershipTypeIndex !== null &&
12847            (
12848                (
12849                    in_array($membershipTypeIndex, Configure::read('store_credit_form_memberships')) && 
12850                    !empty($userData['User']['corporate_id'])
12851                ) || 
12852                in_array($membershipTypeIndex, Configure::read('common_corporate_payment_memberships'))
12853            )
12854        ) {
12855            if ($fromUnliOption) {
12856                return $this->redirect(myTools::getUrl() . '/mobapp/common_corporate_payment?type=' . Configure::read('payment_url_type.corporate_type.corporate_change_payment_credit') . '&token=' . $apiToken . '&from_page=6&unli_option=' . $fromUnliOption); // 6 is from option page
12857            } else {
12858                return $this->redirect(myTools::getUrl() . '/mobapp/common_corporate_payment?type=' . Configure::read('payment_url_type.corporate_type.corporate_change_payment_credit') . '&token=' . $apiToken. '&from_page=account');
12859            }
12860        }
12861    
12862        // redirect to worldpay if not zuespay user (currency != JPY)
12863        if ($userData['currency_code'] != Configure::read('currency_jpy')) {
12864            return $this->redirect(myTools::getUrl() . '/mobapp/payment/wp_credit_change'.$urlParams);
12865        }
12866
12867        // redirect to family failure page if family plan
12868        if (isset($userData['parent_id']) && $userData['parent_id']) {
12869            return $this->redirect(myTools::getUrl() . '/mobapp/payment/failure_family'.$urlParams);
12870        }
12871
12872        // free user and not corporate individual user
12873        if (
12874            ($userData['charge_flg'] == 0 || $userData['fail_flg'] == 1) &&
12875            !in_array($userData['payment_plan_id'], myTools::getIndividualPaymentPlanIds())
12876        ) {
12877            return $this->redirect(myTools::getUrl() . '/mobapp/payment/credit_retry'.$urlParams);
12878        }
12879
12880        // get request data
12881        $requestData = $this->request->query;
12882
12883        // clear error memcache
12884        $this->memcache->delete('error-'.$apiToken);
12885
12886        // clear previously set card tokens and set new token
12887        $this->memcache->delete('cardchange-token-'.$apiToken);
12888
12889        $cardToken = md5(uniqid(rand(), true));
12890
12891        $this->memcache->set(array(
12892            'key' => 'cardchange-token-'.$apiToken,
12893            'value' => $cardToken,
12894            'expire' => 3600
12895        ));
12896
12897        $userData = $this->changePaymentPlanIfTelecomUser($userData);
12898        // set payment amount
12899        $userData['paymentAmount'] = 0;
12900
12901        // if corporate user
12902        if (isset($userData['corporate_id']) && $userData['corporate_id']) {
12903            $userData['corporateSettlementType'] = Configure::read('corporate_settlement_types.change_card');
12904        }
12905
12906        // set transactin error to 0 if failed to create payment transaction
12907        if (!$pt = $this->createPaymentTransaction($formType, $userData)) {
12908            $this->set('transactionError', 1);
12909        }
12910
12911        // fetch and delete card error
12912        if ($error = $this->memcache->get('card-error-'.$apiToken)) {
12913            $this->memcache->delete('card-error-'.$apiToken);
12914        }
12915        if ($urlRedirect) {
12916            $urlRedirect = "&page_origin=".$urlRedirect;
12917        }
12918
12919        // - NJ-23812 redirect to credit change form
12920        if (isset($fromUnliOption) && !empty($fromUnliOption)) {
12921            $newUrlParams = "?token=".$apiToken.'&cardToken='.$cardToken.'&paymentHash='.$pt['payment_hash'].'&unli_option='.$fromUnliOption;
12922        } else {
12923            $newUrlParams = "?token=".$apiToken.'&cardToken='.$cardToken.'&paymentHash='.$pt['payment_hash'].$urlRedirect;
12924        }
12925
12926        if (!$renderPath) {
12927            return $this->redirect(myTools::getUrl() . '/mobapp/payment/credit_change_form'.$newUrlParams);
12928        }
12929
12930        // set view variables
12931        $this->response->disableCache();
12932        $this->setSupportPayPal($userData);
12933        $this->set('urlRedirect', $urlRedirect);
12934        $this->set('error', $error);
12935        $this->set('cardToken', $cardToken);
12936        $this->set('apiToken', $apiToken);
12937        $this->set('title_for_layout', '再入会');
12938        $this->set('paymentHash', $pt['payment_hash']);
12939        $this->set('userApiToken', $apiToken);
12940
12941        if ($renderPath) {
12942            $this->render($renderPath);
12943        } else {
12944            $this->render(myTools::getDeviceUrl() . 'Payment/credit_change');
12945        }
12946    }
12947
12948    /**
12949     * @api {get} /mobapp/payment/wp_credit_change/:token mobapp_wp_credit_change()
12950     * @apiName mobapp_wp_credit_change
12951     * @apiGroup Payment
12952     * @apiDescription This endpoint is used to redirect to change user's credit card information.
12953     * 
12954     * @apiParam {String} token User's API token
12955     * 
12956     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/wp_credit_change_form
12957     * 
12958     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if token is missing
12959     * 
12960     * @apiSuccessExample Success Response:
12961     * Redirects to {{ENV}}/mobapp/payment/wp_credit_change_form
12962     * 
12963     * @apiErrorExample Error Response:
12964     * Redirects to {{ENV}}/mobapp/retrypage
12965     * 
12966     * @apiSampleRequest off
12967     */
12968    public function mobapp_wp_credit_change() {
12969        $this->blockWithdrawnSapuriToS('mobapp');
12970        $this->disablePageForSapuri('mobapp');
12971        // set variables
12972        $logFileName = 'card_change';
12973        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => Configure::read('payment_credit_change')));
12974        $apiToken = $userData['User']['api_token'];
12975        $this->layout = "mobapp";
12976        $this->response->disableCache();
12977        $urlParams = myTools::getMobappToken($_GET);
12978
12979        // get error from memcache
12980        $error = $this->memcache->get('card_change_error_'.$apiToken);
12981
12982        // check if there is error
12983        if ($error) {
12984            $this->memcache->delete('card_change_error_'.$apiToken);
12985            $this->set('error', $error);
12986        }
12987
12988        // set view variables
12989        $this->set('apiToken', $apiToken);
12990        $this->set('title_for_layout', '再入会');
12991        $this->render(myTools::getDeviceUrl() . 'Payment/wp_credit_change');
12992
12993        // NJ-23812 redirect to change form
12994        return $this->redirect(myTools::getUrl() . '/mobapp/payment/wp_credit_change_form'.$urlParams);
12995    }
12996
12997    /**
12998     * @api {get} /mobapp/payment/wp_credit_change_form/:token mobapp_wp_credit_change_form()
12999     * @apiName mobapp_wp_credit_change_form
13000     * @apiGroup Payment
13001     * @apiDescription This endpoint is used to change user's credit card information.
13002     * 
13003     * @apiParam {String} token User's API token
13004     * 
13005     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/close?token={$apiToken}&type=card_change{$addWelcomeModalParams} afrer successful card change
13006     * 
13007     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if token is missing
13008     * 
13009     * @apiSuccessExample Success Response:
13010     * Redirects to {{ENV}}/mobapp/close?token={$apiToken}&type=card_change{$addWelcomeModalParams}
13011     * 
13012     * @apiErrorExample Error Response:
13013     * Redirects to {{ENV}}/mobapp/retrypage
13014     * 
13015     * @apiSampleRequest off
13016     */ 
13017    public function mobapp_wp_credit_change_form() {
13018        $this->blockWithdrawnSapuriToS('mobapp');
13019        $this->disablePageForSapuri('mobapp');
13020        // set variables
13021        $logFileName = 'card_change';
13022        $formType = Configure::read('payment_credit_change');
13023        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType));
13024        $apiToken = $userData['User']['api_token'];
13025        $user = $this->sharedUserData['User'];
13026        $this->layout = "mobapp";
13027        $this->response->disableCache();
13028        
13029        // get error from memcache
13030        $error = $this->memcache->get('card_change_error_'.$apiToken);
13031        
13032        // check if there is error
13033        if ($error) {
13034            $this->memcache->delete('card_change_error_'.$apiToken);
13035            $this->set('error', $error);
13036        }
13037        
13038
13039        // check if allowed aftee
13040        $this->checkAfteeSupported($userData['User']);
13041        // NJ-23812 : display payment plan 
13042        $this->setPaymentPlanDetails($userData['User'],Configure::read('payment_plans.premium_plan'),$logFileName);
13043
13044        if ($this->Session->read('mobapp_show_welcome_back_modal')) {
13045            $this->Session->delete('mobapp_show_welcome_back_modal');
13046        }
13047
13048        $addWelcomeModalParams = "&re_enrolled=1";
13049
13050        $isCardRegistered = (!empty($user['card_brand']) && !empty($user['card_number'])) ? true : false;
13051        
13052        $this->set('isCardRegistered', $isCardRegistered);
13053        $this->set('cardNumber', $user['card_number']);
13054        $this->set('cardBrand', $user['card_brand']);
13055        $this->set('cardLogo', myTools::getWorldpayCardLogo($user['card_brand']));
13056
13057        // set view variables
13058        $this->set('pmtValue', 'auth');
13059        $this->set('apiToken', $apiToken);
13060        $this->set('logFileName', $logFileName);
13061        $this->set('worldpayFlg', true);
13062        $this->set('memKeyError', 'card_change_error_'.$apiToken);
13063        $this->set('referrer', urlencode(myTools::getUrl()."/mobapp/payment/wp_credit_change_form?token={$apiToken}"));
13064        $this->set('successUrl', urlencode(myTools::getUrl()."/user/mobapp/close?token={$apiToken}&type=card_change{$addWelcomeModalParams}"));
13065        $this->set('formType', $formType);
13066        $this->set('title_for_layout', __d('payment','お支払い方法変更'));
13067        $this->render(myTools::getDeviceUrl() . 'Payment/wp_credit_change_form');
13068    }
13069
13070    /**
13071     * @api {post} /mobapp/payment/credit_change_form/:token/:unli_option/:cardToken/:page_origin/:paymentHash mobapp_credit_change_form()
13072     * @apiName mobapp_credit_change_form
13073     * @apiGroup Payment
13074     * @apiDescription This endpoint is used to process user's credit card information change.
13075     * 
13076     * @apiParam {String} token User's API token
13077     * @apiParam {String} unli_option if User is from unli option. Blank if not provided
13078     * @apiParam {String} cardToken User's card token. Blank if not provided
13079     * @apiParam {Number} page_origin User's page origin. Null if not provided. 1 - store, 2 - ebook
13080     * @apiParam {String} paymentHash User's payment hash.
13081     * 
13082     * @apiBody {String} token User's API token
13083     * @apiBody {Object} ZPaymentFullLogs Payment full logs
13084     * @apiBody {String} ZPaymentFullLogs.card_change Set to 'yes'
13085     * @apiBody {String} ZPaymentFullLogs.telno telephone number of zeus
13086     * @apiBody {String} ZPaymentFullLogs.clientip client ip address
13087     * @apiBody {String} ZPaymentFullLogs.paymentHash User's payment hash
13088     * 
13089     * @apiSuccess {View} Success Redirects to {{ENV}}/mobapp/store/card_register_complete if from store
13090     * @apiSuccess {View} Success Redirects to {{ENV}}//mobapp/option/native-start if from unlimited option
13091     * 
13092     * @apiError {View} Redirect {{ENV}}/mobapp/payment/credit_change?token=  if there's an error
13093     * @apiError {View} Redirect {{ENV}}/mobapp/payment/credit_change_form?token=&page_origin= if user is from store or ebook
13094     * @apiError {View} Redirect {{ENV}}/mobapp/retrypage if payment hash is missing
13095     * 
13096     * @apiSuccessExample Success Response (From Store):
13097     * Redirects to {{ENV}}/mobapp/store/card_register_complete
13098     * 
13099     * @apiSuccessExample Success Response (From Unlimited Option):
13100     * Redirects to {{ENV}}//mobapp/option/native-start
13101     * 
13102     * @apiErrorExample Error Response:
13103     * Redirects to {{ENV}}/mobapp/payment/credit_change?token=
13104     * 
13105     * @apiErrorExample Error Response (From Store or Ebook):
13106     * Redirects to {{ENV}}/mobapp/payment/credit_change_form?token=&page_origin=
13107     * 
13108     * @apiErrorExample Error Response (Payment Hash Missing):
13109     * Redirects to {{ENV}}/mobapp/retrypage
13110     * 
13111     * @apiSampleRequest off
13112     */
13113    public function mobapp_credit_change_form() {
13114
13115        // - NJ-23812
13116        if ($this->Session->read('credit_skip_to_confirmation')) {
13117            $this->Session->delete('credit_skip_to_confirmation');
13118        }
13119
13120        if ($this->Session->read('mobapp_show_welcome_back_modal')){
13121            $this->Session->delete('mobapp_show_welcome_back_modal');
13122        }
13123
13124
13125        $this->blockWithdrawnSapuriToS('mobapp');
13126        $this->disablePageForSapuri('mobapp');
13127        $this->layout = "mobapp";
13128        $urlParams = myTools::getMobappToken($_GET);
13129        $formType = Configure::read('payment_credit_change');
13130        $userData = $this->mobappGetUserData(array('logFileName' => 'card_change', 'formType' => $formType)); // get user data and validate
13131        $apiToken = $this->request->query['token'];
13132        $fromUnliOption = isset($this->request->query['unli_option']) ? $this->request->query['unli_option'] : '';
13133        $cardToken = isset($this->request->query['cardToken']) ? $this->request->query['cardToken'] : '';
13134        $cardToken = isset($this->request->query['cardToken']) ? $this->request->query['cardToken'] : '';
13135        $urlRedirect = isset($this->request->query['page_origin']) ? $this->request->query['page_origin'] : null;
13136        $isZeusUser = isset($userData['card_company']) && $userData['card_company'] == 1 ? true : false;
13137        $userObj = new UserTable($userData);
13138        $membershipTypeIndex = $userObj->getMembershipTypeIndex();
13139        if(
13140            $membershipTypeIndex !== null &&
13141            (
13142                (
13143                    in_array($membershipTypeIndex, Configure::read('store_credit_form_memberships')) && 
13144                    !empty($userData['User']['corporate_id'])
13145                ) || 
13146                in_array($membershipTypeIndex, Configure::read('common_corporate_payment_memberships'))
13147            )
13148        ) {
13149            if ($fromUnliOption) {
13150                return $this->redirect(myTools::getUrl() . '/mobapp/common_corporate_payment?type=' . Configure::read('payment_url_type.corporate_type.corporate_change_payment_credit') . '&token=' . $apiToken . '&from_page=6'); // 6 is from option page
13151            } else {
13152                return $this->redirect(myTools::getUrl() . '/mobapp/common_corporate_payment?type=' . Configure::read('payment_url_type.corporate_type.corporate_change_payment_credit') . '&token=' . $apiToken);
13153            }
13154        }
13155
13156        if (!isset($this->request->query['paymentHash'])) {
13157            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
13158        }
13159
13160        $paymentHash = $this->request->query['paymentHash'];
13161
13162        // delete payment gateway type memcache
13163        $this->memcache->delete('mobappCreditChangePaymentGatewayType_' . $apiToken);
13164
13165        // check if there's a post data
13166        if ($this->request->is('post')) {
13167            $data = $this->request->data;
13168            $data['token'] = $apiToken;
13169            $data['ZPaymentFullLogs']['card_change'] = 'yes';
13170            $data['ZPaymentFullLogs']['telno'] = Configure::read('credit.default_telno');
13171            $data['ZPaymentFullLogs']['clientip'] = Configure::read('ZEUS_clientip');
13172            $data['ZPaymentFullLogs']['paymentHash'] = $paymentHash;
13173
13174            // check url redirect
13175            if ($urlRedirect) {
13176                $data["page_origin"] = $urlRedirect;
13177            }
13178
13179            // check if token matches token in session
13180            $checkToken = $this->checkTokenMobapp($apiToken, $cardToken, 'cardchange-token-');
13181
13182            // check if token is true
13183            if ($checkToken) {
13184                $this->unsetTokenMobapp($apiToken, 'cardchange-token-');
13185                $this->zeus_card_process_mobapp(array(
13186                    'data' => $data,
13187                    'form_type' => $formType,
13188                    'referrer' =>  myTools::getUrl() . "/mobapp/payment/credit_change?token=" . $apiToken,
13189                    'api_token' => $apiToken,
13190                    'unli_option' => $fromUnliOption
13191                ));
13192            } else {
13193                $urlErrRedirect = "/mobapp/payment/credit_change?token=" . $apiToken;
13194                // check for page origin 1 - store, 2 - ebook
13195                if ($urlRedirect) {
13196                    $urlErrRedirect = $urlErrRedirect."&page_origin=".$urlRedirect;
13197                }
13198                // set error message
13199                $this->memcache->set(array(
13200                    'key' => 'card-error-'.$apiToken,
13201                    'value' => 'ERROR : Card validation token mismatch.',
13202                    'expire' => 3600
13203                ));
13204                return $this->redirect(myTools::getUrl() . $urlErrRedirect);
13205            }
13206        }
13207
13208        // NJ-30828: set view to display user's paypal email
13209        $this->setPaypalUser($userData);
13210
13211        // NJ-23812 : set view to display payment plan
13212        $this->setPaymentPlanDetails($userData['User'],Configure::read('payment_plans.premium_plan'),'card_change');
13213        $this->setSupportPayPal($userData['User']);
13214
13215        $this->set('cardBrand', $userData['User']['card_brand']);
13216        $this->set('cardNumber', $userData['User']['card_number']);
13217        $this->set('cardLogo', myTools::getWorldpayCardLogo($userData['User']['card_brand']));
13218        
13219        // - set support paypal
13220        $this->set('paypalUserData', $userData['User']);
13221
13222        // get user data for further processing
13223        $this->set('error', $this->memcache->get('error-'.$apiToken));
13224        $this->set('title_for_layout', '再入会');
13225        $this->set('zeusTransactionFlag', true);
13226        $this->set('amount', 0);
13227        $this->set('paymentHash', $paymentHash);
13228        $this->set('userApiToken', $apiToken);
13229        $this->set('apiToken', $apiToken);
13230        $this->set('title_for_layout', __d('payment','お支払い方法変更'));
13231        $this->set('failURLReferer', myTools::getUrl() . "/mobapp/payment/credit_change" . myTools::getMobappToken(array_merge(array('token' => $apiToken ), $_GET)) );
13232        $this->render(myTools::getDeviceUrl() . 'Payment/credit_change_form');
13233    }
13234    /**
13235     * @api {get} /mobapp/payment/paypal_payment_credit_change_proccess/:token mobapp_paypal_credit_change_process()
13236     * @apiName mobapp_paypal_credit_change_process
13237     * @apiGroup Payment
13238     * @apiDescription This endpoint is used to process user's credit card information change using paypal.
13239     * 
13240     * @apiParam {String} token User's API token
13241     * 
13242     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/close?token={$apiToken}&type=card_change after successful card change
13243     * 
13244     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/payment/credit_change?token= if there's an error
13245     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if token is missing
13246     * 
13247     * @apiSuccessExample Success Response:
13248     * Redirects to {{ENV}}/mobapp/close?token={$apiToken}&type=card_change
13249     * 
13250     * @apiErrorExample Error Response Settlement Failed:
13251     * Redirects to {{ENV}}/mobapp/payment/credit_change?token=
13252     * 
13253     * @apiErrorExample Error Response Token Missing:
13254     * Redirects to {{ENV}}/mobapp/retrypage
13255     * 
13256     * @apiSampleRequest off
13257     */
13258    public function mobapp_paypal_credit_change_process() {
13259        $this->autoRender = false;
13260        $this->layout = false;
13261        $logFileName = 'paypal_debug';
13262
13263        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => Configure::read('payment_credit_change')));
13264        $user = $userData['User'];
13265        $apiToken = $this->request->query['token'];
13266
13267        $data = array(
13268            'paymentPlanData' => array(
13269                'paymentPlanId' => $user['payment_plan_id'],
13270                'priceId' => $user['price_id']
13271            ),
13272            'formType' => Configure::read('payment_credit_change')
13273        );
13274
13275        // process paypal settlement
13276        $result = $this->paypalSaveBillingAgreement($data, $user);
13277
13278        // redirect to reregister page if result is false
13279        if (!$result['success']) {
13280            // set the memcache error
13281            $this->memcache->set(array(
13282                'key' => 'card-error-'.$apiToken,
13283                'value' => __("Error : 決済失敗"),
13284                'expire' => 3600 // 1 hour
13285            ));
13286
13287            $memKey = 'paypalBillingAgreementData_' . $apiToken;
13288
13289            // delete memcache billing agreement data
13290            if ($this->memcache->get($memKey)) {
13291                $this->memcache->delete($memKey);
13292            }
13293
13294            $result['status'] = 0;
13295
13296            // update payment transaction
13297            $this->PaymentTransaction->paypalUpdatePaymentTransaction($result);
13298
13299            $this->memcache->set(array(
13300                'key' => 'mobappCreditChangePaymentGatewayType_' . $apiToken,
13301                'value' => Configure::read('card_company.paypal'),
13302                'expire' => 3600 //  1 hour
13303            ));
13304
13305            return $this->redirect(myTools::getUrl() . "/mobapp/payment/credit_change?token=" . $apiToken);
13306        }
13307
13308        // redirect to notice to user page
13309        return $this->redirect(array('controller' => 'Mobapp', 'action' => 'close', '?' => array('token' => $apiToken, 'type' => 'card_change')));
13310    }
13311
13312    /**
13313     * @api {get} /mobapp/payment/credit_retry/:token mobapp_credit_retry()
13314     * @apiName mobapp_credit_retry
13315     * @apiGroup Payment
13316     * @apiDescription This endpoint is used to display user's credit card retry page.
13317     * 
13318     * @apiParam {String} token User's API token
13319     * 
13320     * @apiSuccess {View} Render Displays user's credit card retry page
13321     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/wp_credit_retry for non-JPY currency users
13322     * 
13323     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if token is missing or empty payment data
13324     * 
13325     * @apiSuccessExample Success Response (JPY Currency):
13326     * Displays user's credit card retry page
13327     * 
13328     * @apiSuccessExample Success Response (Non-JPY Currency):
13329     * Redirects to {{ENV}}/mobapp/payment/wp_credit_retry
13330     * 
13331     * @apiErrorExample Error Response:
13332     * Redirects to {{ENV}}/mobapp/retrypage
13333     * 
13334     * @apiSampleRequest off
13335     */ 
13336    public function mobapp_credit_retry() {
13337
13338        // - NJ-23812 : reset  
13339        if ($this->Session->read('credit_skip_to_confirmation')){
13340            $this->Session->delete('credit_skip_to_confirmation');
13341        }
13342
13343        $this->response->disableCache();
13344        $this->blockWithdrawnSapuriToS('mobapp');
13345        $this->disablePageForSapuri('mobapp');
13346        
13347        // set variables
13348        $this->layout = 'mobapp';
13349        $urlParams = myTools::getMobappToken($_GET);
13350        $logFileName = 'card_retry';
13351        $formType = Configure::read('payment_credit_retry');
13352        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType)); // get user data and validate
13353        $amount = $userData['PaymentPlanPrice']['amount'];
13354        $userData = $userData['User'];
13355        $apiToken = $this->request->query['token'];
13356
13357        $memKeyPaypal = 'mobappPaypalPaymentCreditRetryData_' . $apiToken;
13358        // delete memcache payment gateway type
13359        if ($this->memcache->get($memKeyPaypal)) {
13360            $this->memcache->delete($memKeyPaypal);
13361        }
13362
13363        // delete payment gateway type memcache
13364        $this->memcache->delete('mobappCreditRetryPaymentGatewayType_' . $apiToken);
13365
13366        // - if user is lite plan
13367        $paymentPlanId = $userData['payment_plan_id'];
13368        $isLitePlanUser = in_array($paymentPlanId, Configure::read('lite_payment_plans')) ? true : false;
13369
13370        // - check price id
13371        if (
13372            !isset($userData['price_id']) || 
13373            empty($userData['price_id']) & 
13374            $isLitePlanUser &&
13375            isset($userData['currency_code'])
13376        ) {
13377            $lightPlanData = $this->PaymentPlanPrice->getPaymentData(array(
13378                'currencyCode' => $userData['currency_code'],
13379                'paymentPlanId' => Configure::read('payment_plans.light_plan')
13380            ));
13381
13382            // if empty
13383            if (!$lightPlanData) {
13384                return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
13385            }
13386            
13387            // price id
13388            $userData['price_id'] = $lightPlanData['priceId'];
13389        }
13390
13391        // redirect to retry page if empty payment data and payment plan id or price id is null
13392        if (!$pData = $this->getRetryPaymentData($userData, $logFileName)) {
13393            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
13394        }
13395
13396        
13397
13398        //- new chocotto plan
13399        if ($pData['paymentPlanId'] == Configure::read('payment_plans.chocotto_plan')) {
13400            $formType = Configure::read('payment_credit_chocotto_retry');
13401        }
13402
13403        // redirect to worldpay if not zuespay user (currency != JPY)
13404        if ($userData['currency_code'] != Configure::read('currency_jpy')) {
13405            return $this->redirect(myTools::getUrl() . '/mobapp/payment/wp_credit_retry'.$urlParams);
13406        }
13407
13408        $userData['payment_plan_id'] = $pData['paymentPlanId'];
13409        $userData['price_id'] = $pData['priceId'];
13410        $amount = $pData['amount'];
13411
13412        // NC-3914
13413        $this->getAndSetCardInfo($userData);
13414
13415        // clear error memcache
13416        $this->memcache->delete('error-'.$apiToken);
13417
13418        // clear previously set card tokens and set new token
13419        $this->memcache->delete('cardretry-token-'.$apiToken);
13420
13421        $cardToken = md5(uniqid(rand(), true));
13422
13423        // set memcache
13424        $this->memcache->set(array(
13425            'key' => 'cardretry-token-'.$apiToken,
13426            'value' => $cardToken,
13427            'expire' => 3600
13428        ));
13429
13430        $userData = $this->changePaymentPlanIfTelecomUser($userData);
13431
13432        $corporateIndiUser = false;
13433        $cpAmount = 0;
13434
13435        // - check if empty corporate type -> add corporate type base on user's payment plan id
13436        if (
13437            isset($userData['corporate_id']) &&
13438            $userData['corporate_id'] &&
13439            (!isset($userData['corporate_type']) || !$userData['corporate_type'])
13440        ) {
13441            $userData['corporate_type'] = myTools::getCoporateTypeUsingPaymentPlanId($pData['paymentPlanId']);
13442        }
13443        $corpType = myTools::getCoporateTypeUsingPaymentPlanId($userData['payment_plan_id']);
13444        // if corporate user
13445        if (
13446            isset($userData['corporate_id']) && 
13447            $userData['corporate_id'] &&
13448            isset($userData['payment_plan_id']) &&
13449            $userData['payment_plan_id']
13450        ) {
13451            $corporateTaxRate = Configure::read('tax.increase');
13452            $corporateIndiUser = true;
13453            if ($userData['payment_plan_id'] == Configure::read('payment_plans.corporate_light_individual_plan')) {
13454                $getCorpMemberReceivable = $this->CorporatePaymentMemberReceivable->memberReceivable( array("user_id" => $userData['id']) );
13455                $amount = isset($getCorpMemberReceivable["total"]) ? $getCorpMemberReceivable["total"] : 0 ;
13456                $basicFee = isset($getCorpMemberReceivable["basic_fee"]) ? $getCorpMemberReceivable["basic_fee"] : 0 ;
13457                $basicFeeWoTax = isset($getCorpMemberReceivable["basic_fee_wo_tax"]) ? $getCorpMemberReceivable["basic_fee_wo_tax"] : 0;
13458                $userData['lesson_fee'] = isset($getCorpMemberReceivable["lesson_fee"]) ? $getCorpMemberReceivable["lesson_fee"] : 0 ;
13459                $userData['basic_fee'] = $basicFee ;
13460                $userData['paymentAmount'] = $amount;
13461                $cpAmount = $basicFeeWoTax;
13462                $userData['corporateSettlementType'] = Configure::read('corporate_settlement_types.retry_payment');
13463            } elseif (
13464                $userData['payment_plan_id'] == Configure::read('payment_plans.corporate_standard_individual_plan') ||
13465                $userData['payment_plan_id'] == Configure::read('payment_plans.corporate_premium_individual_plan')
13466            ) {
13467                
13468                $unpaidReceivableParams = array(
13469                    'userId' => $userData['id'],
13470                    'corporateId' => $userData['corporate_id'],
13471                    'corporateType' => $corpType
13472                );
13473
13474                // get unpaid receivable
13475                $unpaidReceivable = $this->CorporatesPaymentReceivable->getIndiUnPaidReceivable($unpaidReceivableParams);
13476
13477                // generate corporate payment receivable if no unpaid corporate payment receivable
13478                if (!$unpaidReceivable) {
13479                    $corpType = $corpType;
13480                    $corpTypeStandard = Configure::read('corporate_type.standard');
13481                    $corpTypePremium = Configure::read('corporate_type.premium');
13482
13483                    $cprTypes = array(
13484                        Configure::read('corporate_type.standard') => $this->CorporatesPaymentReceivable->typeCorporateStandard,
13485                        Configure::read('corporate_type.premium') => $this->CorporatesPaymentReceivable->typeCorporatePremium
13486                    );
13487
13488                    // get payment plan data
13489                    $monthlyPaymentData = $this->PaymentPlanPrice->getPaymentData(array(
13490                        'currencyCode' => $userData['currency_code'],
13491                        'paymentPlanId' => $userData['payment_plan_id']
13492                    ));
13493
13494                    $cprDiscount = (int)$this->CorporateDiscountRate->getDiscount(array(
13495                        'corporateId' => $userData['corporate_id'], 
13496                        'corporateType' => $corpType
13497                    ));
13498
13499                    $insertCPRData = array(
13500                        'corporate_id' => $userData['corporate_id'],
13501                        'user_id' => $userData['id'],
13502                        'type' => isset($cprTypes[$corpType]) ? $cprTypes[$corpType] : 0,
13503                        'status' => 0, // unpaid
13504                        'quantity' => 1,
13505                        'amount' => $monthlyPaymentData['amount'],
13506                        'discount' => $cprDiscount,
13507                        'next_settlement' => date('Y-m-d 00:00:00')
13508                    );
13509
13510                    $unpaidReceivable = array(
13511                        'amount' => $monthlyPaymentData['amount'],
13512                        'discount' => $cprDiscount
13513                    );
13514
13515                    // create corporate payment receivable
13516                    if (!$this->CorporatesPaymentReceivable->addReceivablePayment($insertCPRData)) {
13517                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to create payment receivable.', $userData);
13518                        return ;
13519                    }
13520
13521                }
13522                $amount = $cpAmount = $unpaidReceivable['amount'] - $unpaidReceivable['discount'];
13523                $userData['paymentAmount'] = (int)($amount * $corporateTaxRate);
13524                $amount = (int)($amount * $corporateTaxRate);
13525                $userData['updateCorporateReceivable'] = true;
13526                $userData['corporateSettlementType'] = Configure::read('corporate_settlement_types.retry_payment');
13527            }
13528        } else {
13529            // set payment
13530            $userData['paymentAmount'] = $amount;
13531        }
13532        
13533        // NJ-47740
13534        $coupon = $this->UsersCouponV1->getCouponUseRequest(array(
13535            'userId' => $userData['id'],
13536            'kbn' => Configure::read('coupon_kbn.monthly_settlement')
13537        ));
13538        
13539        if (
13540            !empty($coupon['result']) && 
13541            !empty($coupon['grp_id']) && 
13542            !empty($coupon['amount']) && 
13543            empty($coupon['has_payment']) // exclude if coupon has payment
13544        ) {
13545            $userData['monthlyDiscount'] = $coupon['amount'];
13546            $userData['monthly_grp_id'] = $coupon['grp_id'];
13547        }
13548        // NJ-47740 end
13549
13550        // NJ-23812: set receivable
13551        $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userData['id']);
13552        $appreciationPayment = $this->PaymentReceivable->computeReceivableReservationPayment($userData['id'], false, Configure::read('appreciation_data.payment_element_type'));
13553        $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userData['id'], false, Configure::read('payment_element_type.live'));
13554
13555        // add reserve receivable
13556        $userData['paymentAmount'] += $receivablePayment;
13557
13558        // add appreciation lesson receivable
13559        $userData['paymentAmount'] += $appreciationPayment;
13560
13561        // add live lesson receivable
13562        $userData['paymentAmount'] += $liveLessonReceivable;
13563
13564        // get user active annual discount option
13565        $annualDiscountOptionData = $this->UserDiscountOptionsTerm->getTerm([
13566            'user_id' => $userData['id'],
13567            'discount_option_id' => Configure::read('discount_option.annual.plan_id'),
13568            'status' => 1
13569        ]);
13570
13571        if ($annualDiscountOptionData) {
13572            unset($annualDiscountOptionData['contract_start']);
13573            $annualDiscountOptionData += [
13574                'dosh_event' => Configure::read('discount_option.dosh_event.annual_discount'),
13575                'dosh_status' => Configure::read('discount_option.dosh_status.monthly_discount')
13576            ];
13577            $userData['annualDiscountOption'] = $annualDiscountOptionData;
13578            $userData['paymentAmount'] -= $annualDiscountOptionData['amount'];
13579        }
13580
13581        // set transaction error to 1 if failed to create payment transaction
13582        if (!$pt = $this->createPaymentTransaction($formType, $userData)) {
13583            $this->set('transactionError', 1);
13584        }
13585
13586        // fetch and delete card error
13587        if ($error = $this->memcache->get('card-error-'.$apiToken)) {
13588            $this->memcache->delete('card-error-'.$apiToken);
13589        }
13590
13591        $sessionPaypalParams = array(
13592            'token' => "",
13593            'payment_gateway_type' => Configure::read('card_company.paypal'),
13594            'ZPaymentFullLogs' => array(
13595                'money' => $amount,
13596                'paymentHash' => $pt['payment_hash'],
13597                'discounted_amount' => (isset($userData['discounted_amount'])) ? $userData['discounted_amount'] : 0,
13598                'monthlyDiscount' => (isset($userData['monthlyDiscount'])) ? $userData['monthlyDiscount'] : 0,
13599                'monthly_grp_id' => (isset($userData['monthly_grp_id'])) ? $userData['monthly_grp_id'] : 0
13600            ),
13601            'paymentPlanData' => $pData,
13602            'receivablePayment' => $receivablePayment,
13603            'appreciationReceivable' => $appreciationPayment,
13604            'liveLessonReceivable' => $liveLessonReceivable,
13605            'liveLessonReceivable' => $liveLessonReceivable,
13606            'formType' => $formType
13607        );
13608
13609        if ($annualDiscountOptionData) {
13610            $sessionPaypalParams['annualDiscountOption'] = $annualDiscountOptionData;
13611        }
13612
13613        // NC-7029: coupon discount        
13614        if (!empty($userData['monthlyDiscount']) && !empty($userData['monthly_grp_id'])) {
13615            $sessionPaypalParams['monthlyDiscount'] = $userData['monthlyDiscount'];
13616            $sessionPaypalParams['monthly_grp_id'] = $userData['monthly_grp_id'];
13617        }
13618
13619        $this->memcache->set(array(
13620            'key' => 'mobappPaypalPaymentCreditRetryData_' . $apiToken,
13621            'value' => $sessionPaypalParams,
13622            'expire' => 3600 // 1 hour
13623        ));
13624
13625        // NJ-30828: set view to display user's paypal email
13626        $this->setPaypalUser($userData);
13627
13628        // NJ-23812 : set view var 
13629        $this->set('corporateIndiUser', $corporateIndiUser);
13630        $this->set('cpAmount',$cpAmount);
13631        $this->set('ppFormatAmount',number_format($amount));
13632
13633        // - NJ-23812 : support paypal
13634        $this->setSupportPayPal($userData);
13635        $this->set('paypalFlg', true);
13636        $this->set('paypalUserData', $userData);
13637        $this->set('userApiToken', $apiToken);
13638        $this->set('fAmount', myTools::formatAmount($amount));
13639
13640        $currencyData = $this->Currency->getSymbolAndPosition($user['currency_code']);
13641        $this->set('currencyData', $currencyData);
13642        $this->set('monthlyPriceSymbol',myTools::getCurrencySymbol($user['currency_code']));
13643
13644        // set view variables
13645        $this->set('data', $this->memcache->get('mobappUserCreditRetryInfo_'.$apiToken));
13646        $this->set('error', $error);
13647        $this->set('cardToken', $cardToken);
13648        $this->set('apiToken', $apiToken);
13649        $this->set('title_for_layout', __d('payment','お支払い方法変更'));
13650        $this->set('zeusTransactionFlag', true);
13651        $this->set('paymentHash', $pt['payment_hash']);
13652        $this->set('amount', $amount);
13653        $this->set('discountedAmount', (isset($userData['discounted_amount']) ? $userData['discounted_amount'] : 0));
13654        $this->set('failURLReferer', myTools::getUrl() . "/mobapp/payment/credit_retry" . myTools::getMobappToken(array_merge(array('token' => $apiToken ), $_GET)) );
13655        $this->render(myTools::getDeviceUrl() . 'Payment/credit_retry');
13656    }
13657
13658    /**
13659     * @api {post} /mobapp/payment/credit_retry_form/:token/:cardToken mobapp_credit_retry_form()
13660     * @apiName mobapp_credit_retry_form
13661     * @apiGroup Payment
13662     * @apiDescription This endpoint is used to process user's credit card retry form.
13663     * 
13664     * @apiParam {String} token User's API token
13665     * @apiParam {String} cardToken User's card token
13666     * 
13667     * @apiBody {Number} payment_gateway_type The type of payment gateway selected
13668     * @apiBody {Object} discountOption The annual discount option data, if available.
13669     * @apiBody {Number} discountOption.user_id The ID of the user.
13670     * @apiBody {Number} discountOption.discount_option_id The ID of the discount option.
13671     * @apiBody {Number} discountOption.status The status of the discount option.
13672     * @apiBody {Number} discountOption.dosh_event The event associated with the discount option.
13673     * @apiBody {Number} discountOption.dosh_status The status of the discount option.
13674     * @apiBody {Object} paymentPlanData The payment plan data for the user. required if paypal payment gateway is selected.
13675     * @apiBody {Number} paymentPlanData.paymentPlanId The ID of the payment plan.
13676     * @apiBody {Number} paymentPlanData.priceId The ID of the price.
13677     * @apiBody {Number} receivablePayment The receivable payment data.
13678     * @apiBody {Number} appreciationReceivable The appreciation payment receivable data.
13679     * @apiBody {Number} liveLessonReceivable The live lesson payment receivable data.
13680     * @apiBody {Number} formType The form type. Sets to 4 for credit retry.
13681     * @apiBody {Number} discounted_amount The total discounted amount from the coupon.
13682     * @apiBody {String} coupon_used The coupon used for the discount.
13683     * @apiBody {String} token The API token.
13684     * @apiBody {Object} ZPaymentFullLogs The payment full logs data.
13685     * @apiBody {String} ZPaymentFullLogs.clientip The client IP address.
13686     * @apiBody {String} ZPaymentFullLogs.telno The default telephone number.
13687     * @apiBody {String} cardToken The card token.
13688     * 
13689     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/paypal_payment_credit_retry_confirm?token={$apiToken} after successful card retry
13690     * 
13691     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if empty payment data and payment plan id or price id is null
13692     * 
13693     * @apiExample Example usage:
13694     * {
13695     *      "payment_gateway_type": 1
13696     *      "discountOption": {
13697     *            "user_id": 12345,
13698     *            "discount_option_id": 67890,
13699     *            "status": 1,
13700     *            "dosh_event": 1
13701     *            "dosh_status": 2
13702     *      },
13703     *      "receivablePayment": 1000,
13704     *      "appreciationReceivable": 500,
13705     *      "liveLessonReceivable": 300,
13706     *      "formType": "payment_credit_retry",
13707     *      "discounted_amount": 200,
13708     *      "coupon_used": "COUPON123",
13709     *      "token": "api_token_12345",
13710     *      "ZPaymentFullLogs": {
13711     *            "clientip": "192.168.1.1",
13712     *            "telno": "1234567890"
13713     *      },
13714     *      "cardToken": "card_token_12345"
13715     * }
13716     * 
13717     * @apiSuccessExample Success Response:
13718     * Redirects to {{ENV}}/mobapp/payment/paypal_payment_credit_retry_confirm?token={$apiToken}
13719     * 
13720     * @apiErrorExample Error Response:
13721     * Redirects to {{ENV}}/mobapp/retrypage
13722     * 
13723     * @apiSampleRequest off
13724     */
13725    public function mobapp_credit_retry_form(){
13726
13727        // - NJ-23812 : reset  
13728        if ($this->Session->read('credit_skip_to_confirmation')){
13729            $this->Session->delete('credit_skip_to_confirmation');
13730        }
13731
13732        $this->blockWithdrawnSapuriToS('mobapp');
13733        $this->disablePageForSapuri('mobapp');
13734        $this->layout = "mobapp";
13735        $urlParams = myTools::getMobappToken($_GET);
13736        $userData = $this->mobappGetUserData(array('logFileName' => 'card_retry', 'formType' => Configure::read('payment_credit_retry'))); // get user data and validate
13737        $apiToken = $this->request->query['token'];
13738        $cardToken = isset($this->request->query['cardToken']) ? $this->request->query['cardToken'] : '';
13739        $userDataArr = $userData['User'];
13740        $corpType = myTools::getCoporateTypeUsingPaymentPlanId($userDataArr['payment_plan_id']);
13741        $corporateLightBool = ($corpType == Configure::read('corporate_type.light'));
13742
13743        // delete payment gateway type memcache
13744        $this->memcache->delete('mobappCreditRetryPaymentGatewayType_' . $apiToken);
13745
13746        // delete payment paypal data memcache
13747        $this->memcache->delete('mobappPaypalPaymentCreditRetryData_' . $apiToken);
13748
13749        // get user active annual discount option
13750        $annualDiscountOptionData = $this->UserDiscountOptionsTerm->getTerm([
13751            'user_id' => $userDataArr['id'],
13752            'discount_option_id' => Configure::read('discount_option.annual.plan_id'),
13753            'status' => 1
13754        ]);
13755
13756        if ($annualDiscountOptionData) {
13757            unset($annualDiscountOptionData['contract_start']);
13758            $annualDiscountOptionData += [
13759                'dosh_event' => Configure::read('discount_option.dosh_event.annual_discount'),
13760                'dosh_status' => Configure::read('discount_option.dosh_status.monthly_discount')
13761            ];
13762        }
13763
13764        // check if there's a post data
13765        if ($this->request->is('post')) {
13766            $data = $this->request->data;
13767
13768            // add annual discount option data
13769            if ($annualDiscountOptionData) {
13770                $data['discountOption'] = $annualDiscountOptionData;
13771            }
13772
13773            // redirect to paypal confirm page if payment gateway selected is paypal
13774            if ($data['payment_gateway_type'] == Configure::read('card_company.paypal')) {
13775                // redirect to retry page if empty payment data and payment plan id or price id is null
13776                if (!$paymentData = $this->getRetryPaymentData($userDataArr, 'card_retry')) {
13777                    return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
13778                }
13779
13780                $data['paymentPlanData'] = $paymentData;
13781                
13782                // add reserve payment receivable
13783                $data['receivablePayment'] = $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id']);
13784
13785                // add appreciation payment receivable
13786                $data['appreciationReceivable'] = $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('appreciation_data.payment_element_type'));
13787
13788                // add live lesson payment receivable
13789                $data['liveLessonReceivable'] = $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('payment_element_type.live'));
13790
13791                $data['formType'] = Configure::read('payment_credit_retry');
13792                
13793                // NJ-47740
13794                $coupon = $this->UsersCouponV1->getCouponUseRequest(array(
13795                    'userId' => $userDataArr['id'],
13796                    'kbn' => Configure::read('coupon_kbn.monthly_settlement')
13797                ));
13798                
13799                if (
13800                    !empty($coupon['result']) && 
13801                    !empty($coupon['grp_id']) && 
13802                    !empty($coupon['amount']) && 
13803                    empty($coupon['has_payment']) // exclude if coupon has payment
13804                ) {
13805                    $data['discounted_amount'] = $coupon['amount'];
13806                    $data['monthlyDiscount'] = $coupon['amount'];
13807                    $data['monthly_grp_id'] = $coupon['grp_id'];
13808                }
13809                // NJ-47740 end
13810
13811                $this->memcache->set(array(
13812                    'key' => 'mobappPaypalPaymentCreditRetryData_' . $apiToken,
13813                    'value' => $data,
13814                    'expire' => 3600 // 1 hour
13815                ));
13816                return $this->redirect(myTools::getUrl() . '/mobapp/payment/paypal_payment_credit_retry_confirm?token=' . $apiToken);
13817            }
13818
13819            // delete payment gateway type memcache
13820            $this->memcache->delete('mobappCreditRetryPaymentGatewayType_' . $apiToken);
13821
13822            // delete payment paypal data memcache
13823            $this->memcache->delete('mobappPaypalPaymentCreditRetryData_' . $apiToken);
13824
13825            $data['token'] = $apiToken;
13826            $data['ZPaymentFullLogs']['clientip'] = Configure::read('ZEUS_clientip');
13827            $data['ZPaymentFullLogs']['telno'] = Configure::read('credit.default_telno');
13828            $data['cardToken'] = $cardToken;
13829
13830            if ($this->memcache->get('mobappUserCreditRetryInfo_'.$apiToken)) {
13831                $this->memcache->delete('mobappUserCreditRetryInfo_'.$apiToken);
13832            }
13833            $this->memcache->set(array(
13834                'key' => 'mobappUserCreditRetryInfo_'.$apiToken,
13835                'value' => $data,
13836                'expire' => 3600
13837            ));
13838
13839            // NJ-25522: Skip confirm page if using 3D secure challenge
13840            $zeus3DSecureChallengeFlg = $this->memcache->get('zeus3DSecureChallengeFlg_' . $userDataArr['id']);
13841
13842            if ($zeus3DSecureChallengeFlg) {
13843                $formType = Configure::read('payment_credit_retry');
13844
13845                $this->Session->write('mobapp_show_welcome_back_modal',true);
13846
13847                $this->unsetTokenMobapp($apiToken, 'cardretry-token-');
13848                $this->zeus_card_process_mobapp(array(
13849                    'data' => $data,
13850                    'form_type' => $formType,
13851                    'referrer' =>  array('controller' => 'Payment', 'action' => 'mobapp_credit_retry', '?' => array('token' => $apiToken)),
13852                    'api_token' => $apiToken
13853                ));
13854            }
13855            return $this->redirect(myTools::getUrl() . '/payment/mobapp_credit_retry_confirm'.$urlParams);
13856        } else {
13857            // delete payment gateway type memcache
13858            $this->memcache->delete('mobappCreditRetryPaymentGatewayType_' . $apiToken);
13859
13860            $this->set('data', $this->memcache->get('mobappUserCreditRetryInfo_'.$apiToken));
13861        }
13862
13863        if (!isset($this->request->query['amount']) || !isset($this->request->query['paymentHash'])) {
13864            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
13865        }
13866        $amount = $this->request->query['amount'];
13867
13868        // NJ-23812 : set suport paypal
13869        $this->setSupportPayPal($userData['User']);
13870        $this->set('userApiToken',$apiToken);
13871        $this->set('paypalUserData',$userData['User']);
13872
13873
13874        //get user data for further processing
13875        $this->set('cardToken', $cardToken);
13876        $this->set('apiToken', $apiToken);
13877        $this->set('error', $this->memcache->get('error-'.$apiToken));
13878        $this->set('title_for_layout', __d('payment','お支払い方法変更'));
13879        $this->set('zeusTransactionFlag', true);
13880        $this->set('amount', $amount);
13881        $this->set('paymentHash', $this->request->query['paymentHash']);
13882        $this->set('discountedAmount', (isset($this->request->query['discountedAmount']) ? $this->request->query['discountedAmount'] : 0));
13883        $this->set('failURLReferer', myTools::getUrl() . "/mobapp/payment/credit_retry_form" . myTools::getMobappToken(array_merge(array('token' => $apiToken ), $_GET)) );
13884        $this->render(myTools::getDeviceUrl() . 'Payment/credit_retry_form');
13885    }
13886
13887    /**
13888     * @api {post} /mobapp/payment/wp_credit_retry/:api_token mobapp_wp-credit_retry()
13889     * @apiName mobapp_wp_credit_retry
13890     * @apiGroup Payment
13891     * @apiDescription this endpoint is used to process the credit card retry for worldpay
13892     * 
13893     * @apiParam {String} api_token user's api token
13894     * 
13895     * @apiBody {Number} cardType card type (0: existing card, 1: new card)
13896     * 
13897     * @apiSuccess {View} Redirect Redirect to {{ENV}}/mobapp_wp_credit_retry_form for new card
13898     * @apiSuccess {View} Rediect Redirect to {{ENV}}/mobapp_wp_credit_retry_confirm?token= for existing card
13899     * 
13900     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage for empty token
13901     * 
13902     * @apiExample {json} Example usage:
13903     * {
13904     *         "cardType": 0
13905     * }
13906     * 
13907     * @apiSuccessExample Success Response New card:
13908     * Redirects to {{ENV}}/mobapp_wp_credit_retry_form for new card
13909     * 
13910     * @apiSuccessExample Success Response Existing card:
13911     * Redirects to {{ENv}}/mobapp_wp_credit_retry_confirm?token= for existing card
13912     * 
13913     * @apiErrorExample Error Response:
13914     * Redirects to {{ENV}}/mobapp/retrypage for empty token
13915     * 
13916     * @apiSampleRequest off
13917     */
13918    public function mobapp_wp_credit_retry() {
13919
13920        if ($this->Session->read('credit_skip_to_confirmation')) {
13921            $this->Session->delete('credit_skip_to_confirmation');
13922        }
13923
13924        $this->blockWithdrawnSapuriToS('mobapp');
13925        $this->disablePageForSapuri('mobapp');
13926        // set variables
13927        $logFileName = 'card_retry';
13928        $formType = Configure::read('payment_credit_retry');
13929        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType));
13930        $userData = $userData['User'];
13931        $this->layout = "mobapp";
13932        $this->response->disableCache();
13933        $apiToken = $userData['api_token'];
13934        $memKey = "credit_retry_{$userData['id']}_{$userData['currency_code']}";
13935        $cardType = $this->memcache->get($memKey);
13936        $cardType = isset($cardType) ? $cardType : 0;
13937
13938        if ($this->request->is('post')) {
13939            $cardType = $this->request->data['cardType'];
13940
13941            // memcache card type value
13942            $this->memcacheCardType(array(
13943                'key' => $memKey,
13944                'value' => $cardType
13945            ));
13946
13947            // redirect to hosted page if using new card ($cardType = 1)
13948            if ($cardType) {
13949                 $this->redirect(myTools::getUrl() . "/mobapp/payment/wp_credit_retry_form".myTools::getMobappToken($_GET));
13950            // redirect to confirm page if using existing card ($cardType = 0)
13951            } else {
13952
13953                // - NJ-23812: write session to skip and auto charge 
13954                $this->Session->write('credit_skip_to_confirmation',true);
13955
13956                $this->redirect(myTools::getUrl() . "/mobapp/payment/wp_credit_retry_confirm?token=$apiToken");
13957            }
13958        }
13959
13960    
13961        // - NJ-23812 : redirect to form
13962        $this->redirect(myTools::getUrl() . "/mobapp/payment/wp_credit_retry_form".myTools::getMobappToken($_GET));
13963
13964        // set view variables
13965        $this->set('cardLogo', myTools::getWorldpayCardLogo($userData['card_brand']));
13966        $this->set('cardBrand', $userData['card_brand']);
13967        $this->set('cardNumber', $userData['card_number']);
13968        $this->set('cardType', $cardType);
13969        $this->set('apiToken', $apiToken);
13970        $this->set('user', $userData);
13971        $this->set('title_for_layout', '再入会');
13972        $this->render(myTools::getDeviceUrl() . 'Payment/wp_credit_retry');
13973    }
13974
13975    /**
13976     * @api {get} /mobapp/payment/wp_credit_retry_form/:api_token mobapp_wp_credit_retry_form()
13977     * @apiName mobapp_wp_credit_retry_form
13978     * @apiGroup Payment
13979     * @apiDescription This endpoint is used to process the credit card retry for worldpay
13980     * 
13981     * @apiParam {String} api_token user's api token
13982     * 
13983     * @apiSuccess {View} Redirect Redirect to {{ENV}}/mobapp/payment/credit_retry_complete?token={$apiToken}&type=credit_retry_complete{$addWelcomeModal} for success
13984     * 
13985     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage for empty token
13986     * 
13987     * @apiSampleRequest off
13988     */
13989    public function mobapp_wp_credit_retry_form() {
13990        $this->blockWithdrawnSapuriToS('mobapp');
13991        $this->disablePageForSapuri('mobapp');
13992        // set variables
13993        $logFileName = 'card_retry';
13994        $formType = Configure::read('payment_credit_retry');
13995        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType));
13996        $apiToken = $userData['User']['api_token'];
13997        $this->layout = "mobapp";
13998        $this->response->disableCache();
13999
14000        // check if allowed aftee
14001        $this->checkAfteeSupported($userData['User']);
14002
14003        // - NJ-23812: start support 
14004        $user = $userData['User'];
14005        $memKey = "credit_retry_{$userData['id']}_{$userData['currency_code']}";
14006        $cardType = $this->memcache->get($memKey);
14007        $cardType = isset($cardType) ? $cardType : 0;
14008
14009        // get error from memcache
14010        $error = $this->memcache->get('card_retry_error_' . $apiToken);
14011
14012        // check and set if there is error
14013        if ($error) {
14014            $this->memcache->delete('card_retry_error_' . $apiToken);
14015            $this->set('error', $error);
14016        }
14017
14018        // - set payment plan details 
14019        $pData = $this->getRetryPaymentData($user, 'card_retry');
14020        $isCardRegistered = (!empty($user['card_brand']) && !empty($user['card_number'])) ? true : false;
14021        $comPlanUser = (isset($user['com_plan_user']) && $user['com_plan_user']) ? $user['com_plan_user'] : false;
14022
14023        // set view variables
14024        $this->set('isCardRegistered',$isCardRegistered);
14025        $this->set('cPlan', $comPlanUser);
14026        $this->set('fAmount', $pData['fAmount']);
14027        $this->set('cardLogo', myTools::getWorldpayCardLogo($user['card_brand']));
14028        $this->set('cardType', $cardType);
14029        $this->set('user', $user);
14030        $this->set('title_for_layout', '再入会');
14031
14032        if ($this->Session->read('mobapp_show_welcome_back_modal')) {
14033            $this->Session->delete('mobapp_show_welcome_back_modal');
14034        }
14035
14036        $addWelcomeModal = "&re_enrolled=1";
14037
14038        // set view vars
14039        $this->set('cardBrand', $user['card_brand']);
14040        $this->set('cardNumber', $user['card_number']);
14041        $this->set('pmtValue', 'payment');
14042        $this->set('apiToken', $apiToken);
14043        $this->set('logFileName', $logFileName);
14044        $this->set('worldpayFlg', true);
14045        $this->set('memKeyError', 'card_retry_error_'.$apiToken);
14046        $this->set('referrer', urlencode(myTools::getUrl()."/mobapp/payment/wp_credit_retry_form?token={$apiToken}"));
14047        $this->set('successUrl', urlencode(myTools::getUrl()."/mobapp/payment/credit_retry_complete?token={$apiToken}&type=credit_retry_complete{$addWelcomeModal}"));
14048        $this->set('formType', $formType);
14049        $this->render(myTools::getDeviceUrl() . 'Payment/wp_credit_retry_form');
14050    }
14051    /**
14052     * @api {post} /mobapp/payment/wp_credit_retry_confirm/:token mobapp_wp_credit_retry_confirm()
14053     * @apiName mobapp_wp_credit_retry_confirm
14054     * @apiGroup Payment
14055     * @apiDescription This endpoint is used to process the credit card retry for worldpay
14056     * 
14057     * @apiParam {String} token user's api token
14058     * 
14059     * @apiSuccess {View} Redirect Redirect to {{ENV}}/mobapp/payment/credit_retry_complete?token=$apiToken&type=credit_retry_complete for success
14060     * 
14061     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage
14062     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/payment/wp_credit_retry?token= for direct payment response is not authorised 
14063     * 
14064     * @apiSuccessExample Success Response:
14065     * Redirects to {{ENV}}/mobapp/payment/credit_retry_complete?token=$apiToken&type=credit_retry_complete
14066     * 
14067     * @apiErrorExample Error Response If direct payment response is not authorised:
14068     * Redirects to {{ENV}}/mobapp/payment/wp_credit_retry?token=
14069     * 
14070     * @apiErrorExample Error Response:
14071     * Redirects to {{ENV}}/mobapp/retrypage
14072     * 
14073     * @apiSampleRequest off
14074     */
14075    public function mobapp_wp_credit_retry_confirm() {
14076        // set variables
14077        $logFileName = 'card_retry';
14078        $formType = Configure::read('payment_credit_retry');
14079        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType));
14080        $this->layout = "mobapp";
14081        $this->response->disableCache();
14082        $amount = $userData['PaymentPlanPrice']['amount'];
14083        $userData = $userData['User'];
14084        $memKey = "credit_retry_{$userId}_{$currencyCode}";
14085        $urlParams = myTools::getMobappToken($_GET);
14086
14087        $userId = $userData['id'];
14088        // redirect to retry page if empty payment data and payment plan id or price id is null
14089        if (!$pData = $this->getRetryPaymentData($userData, $logFileName)) {
14090            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed getRetryPaymentData --> ' . json_encode($userData), 'error');
14091            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
14092        }
14093
14094        $currencyCode = $userData['currency_code'];
14095        $apiToken = $userData['api_token'];
14096        $userData['payment_plan_id'] = $pData['paymentPlanId'];
14097        $userData['price_id'] = $pData['priceId'];
14098        $amount = $pData['amount'];
14099
14100        $currency_before = $userData['currency_code'];
14101        $plan_before = $userData['payment_plan_id'];
14102
14103        $readSkipConfirmation = true;//NJ-23812:force skip view the confirmation page
14104    
14105
14106        if ($this->request->is('post') || $readSkipConfirmation) {
14107            
14108            // NJ-47740
14109            $coupon = $this->UsersCouponV1->getCouponUseRequest(array(
14110                'userId' => $userId,
14111                'kbn' => Configure::read('coupon_kbn.monthly_settlement')
14112            ));
14113            
14114            if (
14115                !empty($coupon['result']) && 
14116                !empty($coupon['grp_id']) && 
14117                !empty($coupon['amount']) && 
14118                empty($coupon['has_payment']) // exclude if coupon has payment
14119            ) {
14120                $amount -= $userData['discounted_amount'] = $coupon['amount'];
14121                $userData['monthlyDiscount'] = $coupon['amount'];
14122                $userData['monthly_grp_id'] = $coupon['grp_id'];
14123            }
14124            // NJ-47740 end
14125
14126            // get reserve payment receivable
14127            $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userId);
14128
14129            // get appreciation lesson payment receivable
14130            $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('appreciation_data.payment_element_type'));
14131
14132            // get live lesson payment receivable
14133            $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.live'));
14134
14135            // add retry payment, receivable payment amount and live lesson payment receivable
14136            $totalAmount = $amount + $receivablePayment + $appreciationReceivable + $liveLessonReceivable;
14137            $orderCode = myTools::generateOrderCode($userId);
14138
14139            $paymentMethodType = myTools::getWPPaymentMethodType($userData['card_brand'], 'payment');
14140            $merchantCode = myTools::getWPMerchantCode($paymentMethodType);
14141            $paymentMethod = explode('_', $paymentMethodType);
14142            $paymentMethod = isset($paymentMethod[0]) ? $paymentMethod[0] : null;
14143            $currencyExponents = Configure::read('worldpay.currency_exponents');
14144            $exponent = $currencyExponents[$currencyCode];
14145
14146            // get total amount with checking currency exponent
14147            $totalAmountArr = myTools::wpGetAmount($exponent, $totalAmount);
14148            $ncAmount = $totalAmountArr['ncAmount'];
14149            $wpAmount = $totalAmountArr['wpAmount'];
14150
14151            $wpData = array(
14152                'cardToken' => $userData['card_token'],
14153                'merchantCode' => $merchantCode,
14154                'paymentHash' => $orderCode,
14155                'wpPaymentAmount' => $wpAmount
14156            );
14157
14158            // set payment amount
14159            $userData['paymentAmount'] = $ncAmount;
14160
14161            // create payment transaction
14162            if (!$pt = $this->createPaymentTransaction($formType, $userData, $wpData)) {
14163                $this->log(__METHOD__ .' Failed to save payment transaction. Params --> ' . json_encode($wpData), $logFileName);
14164                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to save payment transaction. Params --> ' . json_encode($wpData), 'error');
14165                return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
14166            }
14167
14168            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - After save payment transaction. Params --> ' . json_encode($wpData), 'error');
14169
14170            // if aftee payment
14171            if (
14172                $userData['card_company'] == Configure::read('card_company.aftee') ||
14173                ($userData['card_brand'] == "AFTEE" && !empty($userData['aftee_transaction_identifier']))
14174            ) {
14175
14176                // default result
14177                $checkRes = array(
14178                    'OrderCode' => $orderCode,
14179                    'authentication_token' => $userData['card_token'],
14180                    'response' => 'Aftee payment amount is zero',
14181                    'customer' => array(
14182                        'phone_number' =>  $userData['phone_number']
14183                    )
14184                );
14185                $receivableResult = json_encode($checkRes);
14186                $afteeTransactionIdentifier = $userData['aftee_transaction_identifier'];
14187
14188
14189                if ($userData['paymentAmount'] > 0) {
14190
14191                    if (!class_exists('AfteePaymentService')) {
14192                        App::uses('AfteePaymentService','Lib');
14193                    }
14194                    $afteeService = new AfteePaymentService();
14195                    $afteeChecksumData = array(
14196                        'shopItemId' => "AFTEE" . $formType,
14197                        'itemName' => 'CreditRetryUsingExistingCard',
14198                        'itemPrice' => $totalAmount,
14199                        'itemCount' => 1,
14200                        'customerPhoneNumber' => $userData['phone_number'],
14201                        'customerEmail' => $userData['email'],
14202                        'shopTransactionNo' => $orderCode,
14203                        'userID' =>  $userData['id']
14204                    );
14205                    $checksum = $afteeService->generateChecksum($afteeChecksumData, false);
14206                    $afteeData = array(
14207                        'authentication_token' => $userData['card_token'],
14208                        'related_id' => $userData['aftee_transaction_identifier'],
14209                        'checksum' => $checksum['checksum'],
14210                        'shop_transaction_no' => $orderCode,
14211                        'transaction_options' => array(1)
14212                    );
14213
14214                    $afteePaymentData = array_merge($afteeData, $checksum['settlementData']);
14215
14216                    // aftee execute payment
14217                    $receivableResult = $afteeService->directPayment($afteePaymentData);
14218                    $checkRes = json_decode($receivableResult, true);
14219
14220
14221                    if ( isset($checkRes['object']) && $checkRes['object'] == 'transaction') {
14222                        $prPaymentSuccess = true;
14223                    } else if ( !array_key_exists("object", $checkRes) || (isset($checkRes['object']) && $checkRes['object'] == 'error')) {
14224                        $prPaymentSuccess = false;
14225                    }
14226
14227                    $afteeTransactionIdentifier = isset($checkRes['id']) && !empty($checkRes['id']) ? $checkRes['id'] : NULL;
14228                    if (isset($checkRes['related_transaction']) && !empty($checkRes['related_transaction'])) {
14229                        $afteeTransactionIdentifier = $checkRes['related_transaction'];
14230                    }
14231                    $orderCode = isset($checkRes['shop_transaction_no']) && !empty($checkRes['shop_transaction_no']) ? $checkRes['shop_transaction_no'] : NULL;
14232                    $checkRes['OrderCode'] = $orderCode;
14233                }
14234
14235                // process payment data
14236                if ($prPaymentSuccess) {
14237                    // set user model
14238                    $uModel = $this->User;
14239                    $dataSource = $uModel->getDataSource();
14240                    $dataSource->begin();
14241
14242                    $afteeParams = array(
14243                        'data' => $checkRes,
14244                        'ptData' => $pt,
14245                        'logFileName' => $logFileName,
14246                        'dataSource' => $dataSource,
14247                        'amount' => $totalAmount,
14248                        'userData' => $userData,
14249                        'transactionIdentifier' => $afteeTransactionIdentifier,
14250                        'aftee' => 1
14251                    );
14252
14253                    $this->processAfteePayment($afteeParams);
14254                }
14255
14256                // update payment transaction
14257                $updateData = array(
14258                    'id' => $pt['id'],
14259                    'fields' => array(
14260                        'status' => $prPaymentSuccess,
14261                        'response_text' => array('aftee_directPayment_response' => $receivableResult))
14262                );
14263
14264                // update payment transaction
14265                $this->PaymentTransaction->updateAfteePaymentTransaction($updateData);
14266
14267
14268                // redirect to payment_credit_charge with error display if direct payment response is not authorised
14269                if (!$prPaymentSuccess) {
14270                    if (!class_exists('myMemcached')) {
14271                        App::uses('myMemcached', 'Lib');
14272                    }
14273                    $memKeyError = 'card_retry_error_' . $apiToken;
14274                    $memerror = __('トランザクションを完了できません。 もう一度お試しください。');
14275                    $memcached = new myMemcached();
14276                    $memcached->set(array(
14277                        'key' => $memKeyError,
14278                        'value' => $memerror,
14279                        'expire' => 3600 // 1 hour
14280                    ));
14281                    return $this->redirect(myTools::getUrl() . '/mobapp/payment/wp_credit_retry?token='.$apiToken);
14282                }
14283            
14284            // worldpay default
14285            } else {
14286
14287                $wpData = array(
14288                    'merchantCode' => $merchantCode,
14289                    'orderCode' => $orderCode,
14290                    'description' => 'Credit Retry Using Existing Card',
14291                    'currencyCode' => $currencyCode,
14292                    'exponent' => $exponent,
14293                    'amount' => $wpAmount,
14294                    'cardToken' => $userData['card_token'],
14295                    'email' => $userData['email'],
14296                    'authenticatedShopperId' => $userId,
14297                    'xmlName' => 'direct_payment_with_token',
14298                    'shopperIpAddress' => $_SERVER["REMOTE_ADDR"],
14299                    'wpTransactionIdentifier' => $userData['wp_transaction_identifier'],
14300                    'paymentMethod' => $paymentMethod
14301                );
14302
14303                $result = wpPaymentService::directPayment($wpData);
14304
14305                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - directPayment result --> ' . json_encode($result), 'error');
14306
14307                $updateData = array(
14308                    'id' => $pt['id'],
14309                    'fields' => array('response_text' => array('directPayment_response' => $result)),
14310                    'logFileName' => $logFileName
14311                );
14312
14313                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - before updatePaymentTransaction result --> ' . json_encode($updateData), 'error');
14314
14315                // update payment transaction direct response
14316                $this->updatePaymentTransaction($updateData);
14317
14318                // redirect to wp_credit_retry with error display if direct payment response is not authorised
14319                if (!myTools::checkIfWPPaymentResponseIsAuthorised($result)) {
14320                    $params = array(
14321                        'apiToken' => $apiToken,
14322                        'wpResponse' => $result,
14323                        'memKey' => 'card_retry_error_' . $apiToken
14324                    );
14325                    myTools::parseAndSetWPErrorResponse($params);
14326                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - WP Payment not authorised --> ' . json_encode($params), 'error');
14327                    return $this->redirect(myTools::getUrl() . '/mobapp/payment/wp_credit_retry?token='.$apiToken);
14328                }
14329
14330                // - flag manual paying user success
14331                UserTable::saveManualPayingUsersToMemcache($userId);
14332
14333            } 
14334
14335            // delete memcache
14336            if ($this->memcache->get($memKey)) {
14337                $this->memcache->delete($memKey);
14338            }
14339            return $this->redirect(myTools::getUrl() . "/mobapp/payment/credit_retry_complete?token=$apiToken&type=credit_retry_complete");
14340        }
14341
14342        // set view variables
14343        $this->set('cardLogo', myTools::getWorldpayCardLogo($userData['card_brand']));
14344        $this->set('apiToken', $apiToken);
14345        $this->set('cardBrand', $userData['card_brand']);
14346        $this->set('cardNumber', $userData['card_number']);
14347        $this->set('amount', $amount);
14348        $this->render(myTools::getDeviceUrl() . 'Payment/wp_credit_retry_confirm');
14349    }
14350    /**
14351     * @api {post} /payment/mobapp_credit_retry_confirm/:token mobapp_credit_retry_confirm()
14352     * @apiName mobapp_credit_retry_confirm
14353     * @apiGroup Payment
14354     * @apiDescription This endpoint is used to confirm the credit card retry
14355     * 
14356     * @apiParam {String} token user's api token
14357     * 
14358     * @apiSuccess {View} Modal Displays the welcome back modal
14359     * 
14360     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage
14361     * 
14362     * @apiSuccessExample Success Response:
14363     * Displays the welcome back modal
14364     * 
14365     * @apiErrorExample Error Response:
14366     * Redirects to {{ENV}}/mobapp/retrypage
14367     * 
14368     * @apiSampleRequest off
14369     */
14370    public function mobapp_credit_retry_confirm() {
14371        $this->layout = 'mobapp';
14372        $formType = Configure::read('payment_credit_retry');
14373        $userData = $this->mobappGetUserData(array('logFileName' => 'card_retry', 'formType' => $formType)); // get user data and validate
14374        $apiToken = $this->request->query['token'];
14375        $userDataArr = $userData['User'];
14376
14377        // redirect to retry page if data does not exist or expired
14378        if (!$data = $this->memcache->get('mobappUserCreditRetryInfo_'.$apiToken)) {
14379            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.myTools::getMobappToken($_GET));
14380        }
14381
14382        $readSkipConfirmation = true; // NJ:23812: mod skipp confirmation page
14383
14384        if ($this->request->is('post') || $readSkipConfirmation) {
14385            // check if token matches token in session
14386            $checkToken = $this->checkTokenMobapp($apiToken, $data['cardToken'], 'cardretry-token-');
14387
14388            // check if payment hash exist in payment transaction table
14389            if (!$pt = $this->PaymentTransaction->getWPPaymentTransaction($data['ZPaymentFullLogs']['paymentHash'])) {
14390                return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
14391            }
14392
14393            // check if token is true
14394            if ($checkToken) {
14395                $ptpp = json_decode($pt['payment_params'], true);
14396                $data['ZPaymentFullLogs']['money'] = (int)$ptpp['paymentAmount'];
14397                $this->Session->write('mobapp_show_welcome_back_modal',true);
14398                $this->unsetTokenMobapp($apiToken, 'cardretry-token-');
14399                $this->zeus_card_process_mobapp(array(
14400                    'data' => $data,
14401                    'form_type' => $ptpp['formType'],
14402                    'referrer' =>  array('controller' => 'Payment', 'action' => 'mobapp_credit_retry', '?' => array('token' => $apiToken)),
14403                    'api_token' => $apiToken
14404                ));
14405            } else {
14406                // set error message
14407                $this->memcache->set(array(
14408                    'key' => 'card-error-'.$apiToken,
14409                    'value' => 'ERROR : Card validation token mismatch.',
14410                    'expire' => 3600
14411                ));
14412                return $this->redirect(array('controller' => 'Payment', 'action' => 'mobapp_credit_retry', '?' => array('token' => $apiToken)));
14413            }
14414        }
14415
14416        if (isset($data['ZPaymentFullLogs']['cardnumber']) && !empty($data['ZPaymentFullLogs']['cardnumber'])) {
14417            $cardNumberArr = str_split($data['ZPaymentFullLogs']['cardnumber'], 4);
14418            $this->set('cardNumber', end($cardNumberArr));
14419        } else {
14420            $this->getAndSetCardInfo($userData['User']);
14421        }
14422
14423        $corporateUser = false;
14424        $corpType = myTools::getCoporateTypeUsingPaymentPlanId($userDataArr['payment_plan_id']);
14425        if (isset($userDataArr['corporate_id']) && isset($corpType)) {
14426            $corporateUser = true;
14427        }
14428
14429        $this->set('corporateType', $corpType);
14430        $this->set('corporateUser', $corporateUser);
14431        $this->set('data', $data);
14432        $this->set('apiToken', $apiToken);
14433        $this->set('amount', myTools::formatAmount($data['ZPaymentFullLogs']['money']));
14434        $this->render(myTools::getDeviceUrl() . 'Payment/credit_retry_confirm');
14435    }
14436    /**
14437     * @api {get} /mobapp/payment/paypal_payment_credit_retry_confirm/:token mobapp_paypal_payment_credit_retry_confirm()
14438     * @apiName mobapp_paypal_payment_credit_retry_confirm
14439     * @apiGroup Payment
14440     * @apiDescription This endpoint is used to display the paypal payment credit retry confirm page
14441     * 
14442     * @apiParam {String} token user's api token
14443     * 
14444     * @apiSuccess {View} Render Displays the paypal payment credit retry confirm page
14445     * 
14446     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage
14447     * 
14448     * @apiSuccessExample Success Response:
14449     * Displays the paypal payment credit retry confirm page
14450     * 
14451     * @apiErrorExample Error Response:
14452     * Redirects to {{ENV}}/mobapp/retrypage
14453     * 
14454     * @apiSampleRequest off
14455     */
14456    public function mobapp_paypal_credit_retry_confirm() {
14457        $this->layout = 'mobapp';
14458        $logFileName = 'paypal_debug';
14459        $formType = Configure::read('payment_credit_retry');
14460
14461        // get user data and validate
14462        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType));
14463        $user = $userData['User'];
14464        $apiToken = $this->request->query['token'];
14465
14466        // redirect to retry page if data does not exist or expired
14467        if (!$data = $this->memcache->get('mobappPaypalPaymentCreditRetryData_' . $apiToken)) {
14468            $this->log(__METHOD__ . ' credit retry data does not exist or expired. user api token --> ' . json_encode($apiToken), $logFileName);
14469            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage' . myTools::getMobappToken($_GET));
14470        }
14471
14472        $this->set('paypalFlg', true);
14473        $this->set('paypalUserData', $userData['User']);
14474        $this->set('fAmount', myTools::formatAmount($data['ZPaymentFullLogs']['money']));
14475        $this->set('userApiToken', $apiToken);
14476
14477        // set payment gateway type
14478        $this->memcache->set(array(
14479            'key' => 'mobappCreditRetryPaymentGatewayType_' . $apiToken,
14480            'value' => $data['payment_gateway_type'],
14481            'expire' => 3600 // 1 hour
14482        ));
14483
14484        $this->render(myTools::getDeviceUrl() . 'Payment/paypal_credit_retry_confirm');
14485    }
14486    /**
14487     * @api {get} /mobapp/payment/mobapp_paypal_credit_retry_process/:token/:negativeTesting mobapp_paypal_credit_retry_process()
14488     * @apiName mobapp_paypal_credit_retry_process
14489     * @apiGroup Payment
14490     * @apiDescription This endpoint is used to process the paypal payment credit retry
14491     * 
14492     * @apiParam {String} token user's api token
14493     * @apiParam {String} negativeTesting Indicates if negative testing is enabled. 1 for enabled, 0 for disabled
14494     * 
14495     * @apiSuccess {View} Redirect Redirect to {{ENV}}/mobapp/payment/credit_retry_complete?token=$apiToken&type=credit_retry_complete for success
14496     * 
14497     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/payment/credit_retry?token=$apiToken for negative testing or payment failed
14498     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage for empty token
14499     * 
14500     * @apiSuccessExample Success Response:
14501     * Redirects to {{ENV}}/mobapp/payment/credit_retry_complete?token=$apiToken&type=credit_retry_complete
14502     * 
14503     * @apiErrorExample Error Response If negative testing or payment failed:
14504     * Redirects to {{ENV}}/mobapp/payment/credit_retry?token=$apiToken
14505     * 
14506     * @apiErrorExample Error Response If empty token:
14507     * Redirects to {{ENV}}/mobapp/payment/credit_retry?token=$apiToken
14508     * 
14509     * @apiSampleRequest off
14510     */
14511    public function mobapp_paypal_credit_retry_process() {
14512        $this->autoRender = false;
14513        $this->layout = false;
14514
14515        $logFileName = 'paypal_debug';
14516        $formType = Configure::read('payment_credit_retry');
14517
14518        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType));
14519        $get = $this->request->query;
14520        $apiToken = $get['token'];
14521        $memKey = 'mobappPaypalPaymentCreditRetryData_' . $apiToken;
14522        $res = array('success' => false);
14523
14524        // redirect to retry page if data does not exist or expired
14525        if (!$data = $this->memcache->get($memKey)) {
14526            $this->log(__METHOD__ . ' credit retry data does not exist or expired. user api token --> ' . json_encode($apiToken), $logFileName);
14527            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage' . myTools::getMobappToken($_GET));
14528        }
14529
14530        // NJ-44815: Resolve mobapp paypal issue coupon discount amount not applied
14531        if (
14532            isset($data['ZPaymentFullLogs']['discounted_amount']) && $data['ZPaymentFullLogs']['discounted_amount'] &&
14533            isset($data['monthlyDiscount']) && $data['monthlyDiscount'] &&
14534            isset($data['monthly_grp_id']) && $data['monthly_grp_id']
14535        ) {
14536            $data['discountedAmount'] = $data['ZPaymentFullLogs']['discounted_amount'];
14537        }
14538
14539        if ((isset($get['negativeTesting']) && $get['negativeTesting']) || !$this->processPayPalPayment($data, $userData['User'])) {
14540            // set the memcache error
14541            $this->memcache->set(array(
14542                'key' => 'card-error-'.$apiToken,
14543                'value' => __("Error : 決済失敗"),
14544                'expire' => 3600 // 1 hour
14545            ));
14546
14547            return $this->redirect('/mobapp/payment/credit_retry?token='.$apiToken);
14548        }
14549
14550        $memKey = 'mobappCreditRetryPaymentGatewayType_' . $apiToken;
14551
14552        // delete memcache payment gateway type
14553        if ($this->memcache->get($memKey)) {
14554            $this->memcache->delete($memKey);
14555        }
14556
14557        UserTable::saveManualPayingUsersToMemcache($userData['User']['id']);
14558        $this->memcache->delete('mobappUserCreditRetryInfo_'.$apiToken);
14559
14560        return $this->redirect(array('controller' => 'Payment', 'action' => 'mobapp_credit_retry_complete', '?' => array('token' => $apiToken, 'type' => 'credit_retry_complete')));
14561    }
14562
14563    /**
14564     * @api {get} /mobapp/payment/credit_register_trial_notice/:token mobapp_credit_register_trial_notice()
14565     * @apiName mobapp_credit_register_trial_notice
14566     * @apiGroup Payment
14567     * @apiDescription This endpoint is used to display the credit card register trial notice page
14568     * 
14569     * @apiParam {String} token user's api token
14570     * 
14571     * @apiSuccess {View} Render Displays the credit card register trial notice page
14572     * 
14573     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage
14574     * 
14575     * @apiSuccessExample Success Response:
14576     * Displays the credit card register trial notice page
14577     * 
14578     * @apiErrorExample Error Response:
14579     * Redirects to {{ENV}}/mobapp/retrypage
14580     * 
14581     * @apiSampleRequest off
14582     */
14583    public function mobapp_credit_register_trial_notice() {
14584        // set variables
14585        $this->layout = 'mobapp';
14586        $logFileName = 'card_reregister';
14587        $formType = Configure::read('payment_credit_authentication');
14588        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType)); // get user data and validate
14589        $userData = $userData['User'];
14590        $userObj = new UserTable($userData);
14591        $apiToken = $this->request->query['token'];
14592
14593        $this->set('token', $apiToken);
14594        $this->set('user', $userData);
14595        $this->set('userObj', $userObj);
14596        $this->render(myTools::getDeviceUrl() . 'Payment/credit_register_trial_notice');
14597    }
14598
14599    /**
14600     * @api {get} /mobapp/payment/credit_register/:token mobapp_credit_register()
14601     * @apiName mobapp_credit_register
14602     * @apiGroup Payment
14603     * @apiDescription This endpoint is used to display the credit card register page
14604     * 
14605     * @apiParam {String} token user's api token
14606     * 
14607     * @apiSuccess {View} Render Displays the credit card register page
14608     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/wp_credit_register if currency is not JPY
14609     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/credit_charge if user is corporate user
14610     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/register/sms_authentication if user has not verified phone number
14611     * 
14612     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage
14613     * 
14614     * @apiSuccessExample Success Response:
14615     * Displays the credit card register page
14616     * 
14617     * @apiSuccessExample Success Response If currency is not JPY:
14618     * Redirects to {{ENV}}/mobapp/payment/wp_credit_register
14619     * 
14620     * @apiSuccessExample Success Response If user is corporate user:
14621     * Redirects to {{ENV}}/mobapp/payment/credit_charge
14622     * 
14623     * @apiSuccessExample Success Response If user has not verified phone number:
14624     * Redirects to {{ENV}}/mobapp/register/sms_authentication
14625     * 
14626     * @apiErrorExample Error Response:
14627     * Redirects to {{ENV}}/mobapp/retrypage
14628     * 
14629     * @apiSampleRequest off
14630     */
14631    public function mobapp_credit_register() {
14632
14633        // - NJ-23812: reset 
14634        if ($this->Session->read('credit_skip_to_confirmation')) {
14635            $this->Session->delete('credit_skip_to_confirmation');
14636        }
14637
14638        //- NJ-27262 : check private page from chocotto
14639        $this->set('enableChocottoPlan', $this->Cookie->read('chocotto_lp'));
14640
14641        $this->response->disableCache();
14642        $this->blockWithdrawnSapuriToS('mobapp');
14643        $this->disablePageForSapuri('mobapp');
14644
14645        // NJ-37156: Cancel plan change to lite plan if user has family added (mobapp)
14646        $hasFamily = json_decode($this->User->checkFamily($this->Session->read('Auth.User.id')), true);
14647        if($hasFamily['status'] != 'normal') {
14648            return $this->redirect(myTools::getUrl().'/mobapp/retrypage'.myTools::getMobappToken($_GET));
14649        }
14650
14651        // set variables
14652        $this->layout = 'mobapp';
14653        $urlParams = myTools::getMobappToken($_GET);
14654        $logFileName = 'card_reregister';
14655        $formType = Configure::read('payment_credit_authentication');
14656        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType)); // get user data and validate
14657        $userData = $userData['User'];
14658        $apiToken = $this->request->query['token'];
14659
14660
14661        // delete payment gateway type memcache
14662        $this->memcache->delete('mobappCreditReregisterPaymentGatewayType_' . $apiToken);
14663        
14664        // redirect to worldpay if not zuespay user (currency != JPY)
14665        if ($userData['currency_code'] != Configure::read('currency_jpy')) {
14666            $this->memcache->delete('success-auth'.$apiToken);
14667            return $this->redirect(myTools::getUrl() . '/mobapp/payment/wp_credit_register'.$urlParams);
14668        }
14669
14670        // no free trial for corporate users
14671        if (!empty($userData['corporate_id'])) {
14672            return $this->redirect(myTools::getUrl() . '/mobapp/payment/credit_charge'.$urlParams);
14673        }
14674
14675        // if has complimentary code
14676        if (!empty($userData['complimentary_code'])) {
14677            $this->set('cPlan', true);
14678        } else {
14679            // NC-3914
14680            $this->getAndSetCardInfo($userData);
14681        }
14682
14683        // get free trial payment data
14684        $freeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
14685            'currencyCode' => $userData['currency_code'],
14686            'paymentPlanId' => Configure::read('payment_plans.free_trial'),
14687            'logFileName' => $logFileName
14688        ));
14689
14690        if (!$freeTrialData) {
14691            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.myTools::getMobappToken($_GET));
14692        }
14693
14694        $user = new UserTable($userData);
14695        $membershipTypes = UserTable::getEngMembershipTypeData();
14696        $membershipTypeIndex = $user->getMembershipTypeIndex();
14697
14698        $userData['price_id'] = $freeTrialData['priceId'];
14699        $userData['payment_plan_id'] = $freeTrialData['paymentPlanId'];
14700        $userData['paymentAmount'] = $freeTrialData['amount'];
14701        $userData['statusBefore'] = $membershipTypes[$membershipTypeIndex];
14702        $userData['statusAfter'] = $membershipTypes[2];
14703
14704        // set transaction error to 1 if failed to create payment transaction
14705        if (!$pt = $this->createPaymentTransaction($formType, $userData)) {
14706            $this->set('transactionError', 1);
14707        }
14708
14709        // clear previously set card tokens and set new card token
14710        $this->unsetTokenMobapp($apiToken, 'card-register-');
14711        $cardToken = md5(uniqid(rand(), true));
14712        $this->memcache->set(array(
14713            'key' => 'card-register-'.$apiToken,
14714            'value' => $cardToken,
14715            'expire' => 3600
14716        ));
14717
14718        // get and delete error from memcache
14719        if ($error = $this->memcache->get('card-error-'.$apiToken)) {
14720            $this->memcache->delete('card-error-'.$apiToken);
14721        }
14722        
14723        // - NJ-23812 : delete previous paypal data
14724        $this->memcache->delete('mobappPaypalPaymentCreditRegisterData_' . $apiToken);
14725
14726        $sessionPaypalParams = array(
14727            'token' => isset($token) ? $token : "",
14728            'payment_gateway_type' => Configure::read('card_company.paypal'),
14729            'ZPaymentFullLogs' => array(
14730                'money' => $freeTrialData['amount'],
14731                'paymentHash' => $pt['payment_hash'],
14732                'discounted_amount' => (isset($discountedAmount)) ? $discountedAmount : 0
14733            ),
14734            'paymentPlanData' => $freeTrialData,
14735            'formType' => $formType
14736        );
14737
14738        $this->memcache->set(array(
14739            'key' => 'mobappPaypalPaymentCreditRegisterData_' . $apiToken,
14740            'value' => $sessionPaypalParams,
14741            'expire' => 3600 // 1 hour
14742        ));
14743
14744        // get monthly price for premium
14745        $pDataDisplay = $this->PaymentPlanPrice->getPaymentData(array(
14746            'currencyCode' => $userData['currency_code'],
14747            'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
14748            'logFileName' => 'card_reregister'
14749        ));
14750
14751        $currencyData = $this->Currency->getSymbolAndPosition($userData['currency_code']);
14752    
14753        // set view display
14754        $this->set('monthlyPrice', myTools::formatAmount($pDataDisplay['amount']));
14755        $this->set('monthylyPriceNoTax',myTools::formatAmount($pDataDisplay['amountConstTaxDeducted']));
14756        $this->set('monthlyPriceSymbol',myTools::getCurrencySymbol($userData['currency_code']));
14757
14758        // - set paypal support 
14759        $this->set('userApiToken', $apiToken); // for paypal_reregister.php (using different variable name)
14760        $this->setSupportPayPal($userData);
14761
14762        $this->set('title_for_layout', __d('register','7日間無料トライアル'));
14763
14764        // NJ-18780 : set view support for lite plan
14765        $this->setLitePaymentInfoView($userData,false,true);
14766
14767        // NJ-30828: set view to display user's paypal email
14768        $this->setPaypalUser($userData);
14769        $annualDiscountOptionData = $this->DiscountOptionsPrice->getPaymentData(['currencyCode' => $userData['currency_code'], 'discountOptionId' => Configure::read('discount_option.annual.plan_id')]);
14770        $annualDiscountOptionAmount = $annualDiscountOptionData ? $annualDiscountOptionData['amount'] : 0;
14771        $monthlyPriceWithAnnualDiscount = $pDataDisplay['amount'] - $annualDiscountOptionAmount;
14772        $monthlyPriceWithAnnualDiscountNoTax = $monthlyPriceWithAnnualDiscount / Configure::read('added_tax_percentage');
14773        $monthlyPriceWithAnnualDiscountNoTax = round($monthlyPriceWithAnnualDiscountNoTax);
14774
14775        $this->set('enableAnnualDiscountOption', $annualDiscountOptionData ? true : false);
14776        $this->set('annualDiscountOptionAmount', myTools::formatAmount($annualDiscountOptionAmount));
14777        $this->set('monthlyPriceWithAnnualDiscount', myTools::formatAmount($monthlyPriceWithAnnualDiscount));
14778        $this->set('monthlyPriceWithAnnualDiscountNoTax', myTools::formatAmount($monthlyPriceWithAnnualDiscountNoTax));
14779
14780        #chocotto plan data
14781        $chocottoPlanData = $this->PaymentPlanPrice->getPaymentData(array(
14782            'currencyCode' => $userData['currency_code'],
14783            'paymentPlanId' => Configure::read('payment_plans.chocotto_plan'),
14784            'logFileName' => $logFileName ?? 'card_register'
14785        ));
14786
14787        // - set chocotto plan price
14788        $this->set('chocottoMonthlyPrice',$chocottoPlanData['fAmount']);
14789        $this->set('chocottoMonthlyPriceNoTax', myTools::formatAmount($chocottoPlanData['amountConstTaxDeducted']));
14790
14791        //- NJ-27262 : check private page from chocotto
14792        $this->set('enableChocottoPlan', $this->Cookie->read('chocotto_lp'));
14793
14794        // set view variables
14795        $this->set('data', $this->memcache->get('mobappUserCreditRegisterInfo_'.$apiToken));
14796        $this->set('error', $error);
14797        $this->set('amount', $freeTrialData['amount']);
14798        $this->set('apiToken', $apiToken);
14799        $this->set('cardToken', $cardToken);
14800        $this->set('zeusTransactionFlag', true);
14801        $this->set('paymentHash', $pt['payment_hash']);
14802        $this->set('title_for_layout', __d('register','7日間無料トライアル'));
14803        $this->set('failURLReferer', myTools::getUrl() . "/mobapp/payment/credit_register" .myTools::getMobappToken(array_merge(array('token' => $apiToken ), $_GET)) );
14804        $this->render(myTools::getDeviceUrl() . 'Payment/credit_register');
14805
14806    }
14807
14808    /**
14809     * @api {post} /mobapp/payment/credit_register_form/:token/:cardToken/:paymentHash mobapp_credit_register_form()
14810     * @apiName mobapp_credit_register_form
14811     * @apiGroup Payment
14812     * @apiDescription This endpoint is used to process the credit card register form
14813     * 
14814     * @apiParam {String} token user's api token
14815     * @apiParam {String} cardToken user's card token
14816     * @apiParam {String} paymentHash user's payment hash
14817     * 
14818     * @apiBody {Number} payment_gateway_type The type of payment gateway selected
14819     * @apiBody {Object} discountOption The annual discount option data, if available.
14820     * @apiBody {Number} discountOption.user_id The ID of the user.
14821     * @apiBody {Number} discountOption.discount_option_id The ID of the discount option.
14822     * @apiBody {Number} discountOption.status The status of the discount option.
14823     * @apiBody {Number} discountOption.dosh_event The event associated with the discount option.
14824     * @apiBody {Number} discountOption.dosh_status The status of the discount option.
14825     * @apiBody {Object} paymentPlanData The payment plan data for the user. required if paypal payment gateway is selected.
14826     * @apiBody {Number} paymentPlanData.paymentPlanId The ID of the payment plan.
14827     * @apiBody {Number} paymentPlanData.priceId The ID of the price.
14828     * @apiBody {Number} receivablePayment The receivable payment data.
14829     * @apiBody {Number} appreciationReceivable The appreciation payment receivable data.
14830     * @apiBody {Number} liveLessonReceivable The live lesson payment receivable data.
14831     * @apiBody {Number} formType The form type. Sets to 4 for credit retry.
14832     * @apiBody {Number} discounted_amount The total discounted amount from the coupon.
14833     * @apiBody {String} coupon_used The coupon used for the discount.
14834     * @apiBody {String} token The API token.
14835     * @apiBody {Object} ZPaymentFullLogs The payment log data.
14836     * @apiBody {String} ZPaymentFullLogs.clientip The client IP address.
14837     * @apiBody {String} ZPaymentFullLogs.telno The default telephone number.
14838     * @apiBody {String} cardToken The card token.
14839     * 
14840     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/paypal_payment_credit_register_confirm?token= for paypal payment gateway
14841     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/credit_register_confirm for success
14842     * 
14843     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/payment/credit_register for error or failure
14844     * 
14845     * @apiExample Example usage:
14846     * {
14847     *      "payment_gateway_type": 1
14848     *      "discountOption": {
14849     *            "user_id": 12345,
14850     *            "discount_option_id": 67890,
14851     *            "status": 1,
14852     *            "dosh_event": 1
14853     *            "dosh_status": 2
14854     *      },
14855     *      "receivablePayment": 1000,
14856     *      "appreciationReceivable": 500,
14857     *      "liveLessonReceivable": 300,
14858     *      "formType": "payment_credit_retry",
14859     *      "discounted_amount": 200,
14860     *      "coupon_used": "COUPON123",
14861     *      "token": "api_token_12345",
14862     *      "ZPaymentFullLogs": {
14863     *            "clientip": "192.168.1.1",
14864     *            "telno": "1234567890"
14865     *      },
14866     *      "cardToken": "card_token_12345"
14867     * }
14868     * 
14869     * @apiSuccessExample Success Response For Paypal Payment Gateway:
14870     * Redirects to {{ENV}}/mobapp/payment/paypal_payment_credit_register_confirm?token=
14871     * 
14872     * @apiSuccessExample Success Response:
14873     * Redirects to {{ENV}}/mobapp/payment/credit_register_confirm
14874     * 
14875     * @apiErrorExample Error Response:
14876     * Redirects to {{ENV}}/mobapp/payment/credit_register
14877     * 
14878     * @apiSampleRequest off
14879     */
14880    public function mobapp_credit_register_form() {
14881
14882        if ($this->Session->read('credit_skip_to_confirmation')) {
14883            $this->Session->delete('credit_skip_to_confirmation');
14884        }
14885
14886        $this->blockWithdrawnSapuriToS('mobapp');
14887        $this->disablePageForSapuri('mobapp');
14888        $this->layout = 'mobapp';
14889        $urlParams = myTools::getMobappToken($_GET);
14890        $logFileName = 'card_retry';
14891        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => Configure::read('payment_credit_authentication'))); // get user data and validate
14892        $apiToken = $this->request->query['token'];
14893        $cardToken = isset($this->request->query['cardToken']) ? $this->request->query['cardToken'] : '';
14894
14895        $appVersion = $this->request->query['appVersion'];
14896        $deviceType = $this->request->query['deviceType'];
14897        $this->set('appVersion', $appVersion);
14898        $this->set('deviceType', $deviceType);
14899
14900        // get free trial payment data
14901        $freeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
14902            'currencyCode' => $userData['User']['currency_code'],
14903            'paymentPlanId' => Configure::read('payment_plans.free_trial'),
14904            'logFileName' => $logFileName
14905        ));
14906
14907        if (!$freeTrialData) {
14908            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
14909        }
14910        // Set Data on form load
14911        $data['paymentPlanData'] = $freeTrialData;
14912        $this->memcache->set(array(
14913            'key' => 'mobappPaypalPaymentCreditRegisterData_' . $apiToken,
14914            'value' => $data,
14915            'expire' => 3600 // 1 hour
14916        ));
14917        // check if post data
14918        if ($this->request->is('post')) {
14919            $data = $this->request->data;
14920
14921            // redirect to paypal confirm page if payment gateway selected is paypal
14922            if ($data['payment_gateway_type'] == Configure::read('card_company.paypal')) {
14923                $data['paymentPlanData'] = $freeTrialData;
14924                $this->memcache->set(array(
14925                    'key' => 'mobappPaypalPaymentCreditRegisterData_' . $apiToken,
14926                    'value' => $data,
14927                    'expire' => 3600 // 1 hour
14928                ));
14929                return $this->redirect(myTools::getUrl() . '/mobapp/payment/paypal_payment_credit_register_confirm?token=' . $apiToken);
14930            }
14931
14932            // delete payment gateway type memcache
14933            $this->memcache->delete('mobappCreditReregisterPaymentGatewayType_' . $apiToken);
14934
14935            $data['cardToken'] = $cardToken;
14936            $data['ZPaymentFullLogs']['telno'] = Configure::read('credit.default_telno');
14937            $data['ZPaymentFullLogs']['clientip'] = Configure::read('ZEUS_clientip');
14938            $data['cardToken'] = $cardToken;
14939
14940            // - check if user selected lite plan (1 = lite , 0 = premium)
14941            $paymentPlanType = (isset($data['ZPaymentFullLogs']['payment_plan_type'])) ? (int) $data['ZPaymentFullLogs']['payment_plan_type'] : 0;
14942
14943            if ($paymentPlanType == Configure::read('register_plan_types.light')) {
14944                $userTable = new UserTable($userData['User']);
14945                $_membershipTypes = UserTable::getEngMembershipTypeData();
14946                $_membershipTypeIndex = $userTable->getMembershipTypeIndex();
14947
14948                // - fetch the lite payment plan 
14949                $litefreeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
14950                    'currencyCode' => $userData['User']['currency_code'],
14951                    'paymentPlanId' => Configure::read('payment_plans.light_plan_free'),
14952                    'logFileName' => 'card_reregister'
14953                ));
14954
14955                // - change the price id and payment plan 
14956                $_user = $userData['User'];
14957
14958                $_user['price_id'] = $litefreeTrialData['priceId'];
14959                $_user['payment_plan_id'] = $litefreeTrialData['paymentPlanId'];
14960                $_user['paymentAmount'] = $litefreeTrialData['amount'];
14961                $_user['statusBefore'] = $membershipTypes[$membershipTypeIndex];
14962                $_user['statusAfter'] = $membershipTypes[36]; // - light plan free
14963
14964                $formType = myTools::getLitePlanUserFormType($litefreeTrialData['paymentPlanId']);
14965
14966                // set transaction 
14967                $pt = $this->createPaymentTransaction($formType, $_user);
14968
14969                if ($pt) {
14970                    // - update the payment hash
14971                    $data['ZPaymentFullLogs']['paymentHash'] =    $pt['payment_hash'];
14972                }
14973
14974                // - set data to lite planuser 
14975                $data['isLitePlanUser'] = 1;
14976
14977            //- chocotto plan
14978            } elseif ($paymentPlanType == Configure::read('register_plan_types.chocotto')) {
14979                $userTable = new UserTable($userData['User']);
14980                $_membershipTypes = UserTable::getEngMembershipTypeData();
14981                $_membershipTypeIndex = $userTable->getMembershipTypeIndex();
14982
14983                // - fetch the chocotto payment plan 
14984                $chocottoFreeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
14985                    'currencyCode' => $userData['User']['currency_code'],
14986                    'paymentPlanId' => Configure::read('payment_plans.free_trial_chocotto'),
14987                    'logFileName' => 'card_reregister'
14988                ));
14989
14990                // - change the price id and payment plan 
14991                $_user = $userData['User'];
14992
14993                $_user['price_id'] = $chocottoFreeTrialData['priceId'];
14994                $_user['payment_plan_id'] = $chocottoFreeTrialData['paymentPlanId'];
14995                $_user['paymentAmount'] = $chocottoFreeTrialData['amount'];
14996                $_user['statusBefore'] = $membershipTypes[$membershipTypeIndex];
14997                $_user['statusAfter'] = $membershipTypes[Configure::read('membership_type_chocotto_plan_free')];
14998
14999                $formType = myTools::getChocottoPlanUserFormType($chocottoFreeTrialData['paymentPlanId']);
15000
15001                // set transaction 
15002                $pt = $this->createPaymentTransaction($formType, $_user);
15003
15004                if ($pt) {
15005                    // - update the payment hash
15006                    $data['ZPaymentFullLogs']['paymentHash'] =    $pt['payment_hash'];
15007                }
15008
15009                // - set data to chocotto plan 
15010                $data['isChocottoPlanUser'] = 1;
15011
15012            // if annual discount option
15013            } elseif ($paymentPlanType == Configure::read('register_plan_types.premium_with_annual_discount_option')) {
15014                $annualDiscountOptionData = $this->DiscountOptionsPrice->getPaymentData(['currencyCode' => $userData['User']['currency_code'], 'discountOptionId' => Configure::read('discount_option.annual.plan_id')]);
15015
15016                // redirect to credit page if annual discount option does not exist or is not enabled
15017                if (!$annualDiscountOptionData) {
15018                    return $this->redirect('/');
15019                }
15020
15021                // change amount to 0 since this is a subscription
15022                $annualDiscountOptionData['amount'] = 0;
15023                $annualDiscountOptionData += [
15024                    'dosh_event' => Configure::read('discount_option.dosh_event.annual_discount'),
15025                    'dosh_status' => Configure::read('discount_option.dosh_status.subscription'),
15026                    'option_after_name' => 'Annual Discount Option',
15027                    'option_type' => 3
15028                ];
15029
15030                // update payment transaction (add annual discount option data)
15031                $this->PaymentTransaction->updatePaymentParams(array('paymentHash' => $data['ZPaymentFullLogs']['paymentHash'], 'updateData' => ['discountOption' => $annualDiscountOptionData]));
15032
15033                $data['discountOption'] = $annualDiscountOptionData;
15034            }
15035
15036            if ($this->memcache->get('mobappUserCreditRegisterInfo_'.$apiToken)) {
15037                $this->memcache->delete('mobappUserCreditRegisterInfo_'.$apiToken);
15038            }
15039            $this->memcache->set(array(
15040                'key' => 'mobappUserCreditRegisterInfo_'.$apiToken,
15041                'value' => $data,
15042                'expire' => 3600
15043            ));
15044
15045            //NJ-25522: Skip confirm page if using 3D secure challenge
15046            //NJ-13482 Skip Confirmation Page for New Enrollment
15047            $zeus3DSecureChallengeFlg = $this->memcache->get('zeus3DSecureChallengeFlg_' . $userData['User']['id']);
15048            if (isset($userData['User']['id']) && (!$this->isForTrialReenrollment($userData['User']['id']) || $zeus3DSecureChallengeFlg)) {
15049                $formType = Configure::read('payment_credit_authentication');
15050                $checkToken = $this->checkTokenMobapp($apiToken, $data['cardToken'], 'card-register-');
15051                $this->Session->write('mobapp_show_welcome_back_modal',true);
15052                // check if token is true
15053                if ($checkToken) {
15054                    $this->zeus_card_process_mobapp(array(
15055                        'data' => $data,
15056                        'form_type' => $formType,
15057                        'referrer' =>  array('controller' => 'Payment', 'action' => 'mobapp_credit_register', '?' => array('token' => $apiToken)),
15058                        'api_token' => $apiToken,
15059                        'card_token' => $data['cardToken']
15060                    ));
15061                }
15062            }
15063            return $this->redirect(myTools::getUrl() . '/payment/mobapp_credit_register_confirm'.myTools::getMobappToken(array_merge(array('token' => $apiToken ), $_GET)) );
15064
15065        } else {
15066            // delete payment gateway type memcache
15067            $this->memcache->delete('mobappCreditReregisterPaymentGatewayType_' . $apiToken);
15068
15069            $this->set('data', $this->memcache->get('mobappUserCreditRegisterInfo_'.$apiToken));
15070        }
15071
15072        // check if param payment hash does not exist
15073        if (!isset($this->request->query['paymentHash'])) {
15074            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
15075        }
15076
15077        $paymentHash = $this->request->query['paymentHash'];
15078
15079        // check if payment hash exist in payment transaction table
15080        if (!$this->PaymentTransaction->getWPPaymentTransaction($paymentHash)) {
15081            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
15082        }
15083
15084        // get free trial payment data
15085        $freeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
15086            'currencyCode' => $userData['User']['currency_code'],
15087            'paymentPlanId' => Configure::read('payment_plans.free_trial'),
15088            'logFileName' => $logFileName
15089        ));
15090
15091        if (!$freeTrialData) {
15092            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
15093        }
15094
15095        // set view variables
15096        $this->setSupportPayPal($userData);
15097        $this->set('userApiToken', $apiToken); // for paypal_reregister.php (using different variable name)
15098        $this->set('apiToken', $apiToken);
15099        $this->set('cardToken', $cardToken);
15100        $this->set('zeusTransactionFlag', true);
15101        $this->set('amount', $freeTrialData['amount']);
15102        $this->set('paymentHash', $paymentHash);
15103        $this->set('title_for_layout', '再入会');
15104        $this->set('failURLReferer', myTools::getUrl() . "/mobapp/payment/credit_register".myTools::getMobappToken(array_merge(array('token' => $apiToken ), $_GET)) );
15105        $this->render(myTools::getDeviceUrl() . 'Payment/credit_register_form_new');
15106    }
15107
15108    /**
15109     * @api {post} /payment/credit_register_form sp_credit_register_form()
15110     * @apiName sp_credit_register_form
15111     * @apiGroup Payment
15112     * @apiDescription This endpoint is used to display and process the credit card register form in sp version
15113     * 
15114     * @apiBody {Number} payment_gateway_type The type of payment gateway selected by the user.
15115     * @apiBody {Object} ZPaymentFullLogs Contains additional payment log information.
15116     * @apiBody {String} ZPaymentFullLogs.clientip The client's IP address.
15117     * @apiBody {String} ZPaymentFullLogs.telno The default telephone number.
15118     * @apiBody {Object} [paymentPlanData] Contains payment plan data for the free trial. Used for paypal payment.
15119     * @apiBody {String} [paymentPlanData.currencyCode] The currency code for the payment plan.
15120     * @apiBody {Number} [paymentPlanData.paymentPlanId] The ID of the payment plan.
15121     * @apiBody {Number} [paymentPlanData.amount] The amount for the payment plan.
15122     * 
15123     * @apiSuccess {View} Render Displays the credit card register form
15124     * @apiSuccess {View} Redirect Redirects to {{ENV}}/payment/paypal_payment_credit_register_confirm for paypal payment
15125     * @apiSuccess {View} Redirect Redirects to {{ENV}}/payment/payment_credit_register_confirm for credit card payment
15126     * 
15127     * @apiError {View} Redirect Redirects to {{ENV}}/ if free trial data is missing
15128     * 
15129     * @apiExample {json} Example usage:
15130     * {
15131     *         "payment_gateway_type": 1,
15132     *         "ZPaymentFullLogs": {
15133     *             "clientip": "192.168.1.1"
15134     *             "telno": "1234567890"
15135     *         }
15136     * }
15137     * 
15138     * @apiSuccessExample Success Response:
15139     * Displays the credit card register form
15140     * 
15141     * @apiSuccessExample Success Response If paypal payment:
15142     * Redirects to {{ENV}}/payment/paypal_payment_credit_register_confirm
15143     * 
15144     * @apiSuccessExample Success Response If credit card payment:
15145     * Redirects to {{ENV}}/payment/payment_credit_register_confirm
15146     * 
15147     * @apiErrorExample Error Response:
15148     * Redirects to {{ENV}}/
15149     * 
15150     * @apiSampleRequest off
15151     */
15152    public function sp_credit_register_form() {
15153        $this->blockWithdrawnSapuriToS();
15154        $this->disablePageForSapuri();
15155        $this->checkUser(Configure::read('payment_credit_authentication'));
15156        $logFileName = 'card_reregister';
15157        $userData = $this->sharedUserData;
15158        $apiToken = $userData['User']['api_token'];
15159        // get free trial payment data
15160        $freeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
15161            'currencyCode' => $userData['User']['currency_code'],
15162            'paymentPlanId' => Configure::read('payment_plans.free_trial'),
15163            'logFileName' => $logFileName
15164        ));
15165
15166        if (!$freeTrialData) {
15167            return $this->redirect(myTools::getUrl());
15168        }
15169
15170        if ($this->sharedUserData['User']['currency_code'] == Configure::read('default.user_currency')) {
15171            $this->zeus_credit_register();
15172        // redirect to wp
15173        }
15174        // check if post data
15175        if ($this->request->is('post')) {
15176            $data = $this->request->data;
15177            // redirect to paypal confirm page if payment gateway selected is paypal
15178            if ($data['payment_gateway_type'] == Configure::read('card_company.paypal')) {
15179                $data['paymentPlanData'] = $freeTrialData;
15180                $this->Session->write('paypalPaymentCreditRegisterData', $data);
15181                return $this->redirect(myTools::getUrl() . '/payment/paypal_payment_credit_register_confirm');
15182            }
15183            // delete payment gateway type memcache
15184            $this->memcache->delete('creditReregisterPaymentGatewayType_' . $apiToken);
15185
15186            $data['ZPaymentFullLogs']['clientip'] = Configure::read('ZEUS_clientip');
15187            $data['ZPaymentFullLogs']['telno'] = Configure::read('credit.default_telno');
15188
15189            if ($this->Session->read('PaymentCreditRegisterInfo')) {
15190                $this->Session->delete('PaymentCreditRegisterInfo');
15191            }
15192            $this->Session->write('PaymentCreditRegisterInfo', $data);
15193            return $this->redirect(myTools::getUrl() . '/payment/payment_credit_register_confirm');
15194        } else {
15195            // delete payment gateway type memcache
15196            $data = $this->Session->read('PaymentCreditRegisterInfo');
15197            $this->set('data', $data);
15198        }
15199
15200        // set view variables
15201        $this->set('apiToken', $apiToken);
15202        $this->set('zeusTransactionFlag', true);
15203        $this->set('amount', $freeTrialData['amount']);
15204        // $this->set('paymentHash', $paymentHash);
15205        $renderParam = array(
15206            'forceMobile' => true,
15207            'this' => $this,
15208            'spView' => '/Mobile/Payment/payment_credit_register_form',
15209            'layout' => 'mobile'
15210        );
15211
15212        myTools::render($renderParam);
15213    }
15214    /**
15215     * @api {post} /mobapp/payment/credit_register_confirm/:token mobapp_credit_register_confirm()
15216     * @apiName mobapp_credit_register_confirm
15217     * @apiGroup Payment
15218     * @apiDescription This endpoint is used to process the credit card register confirmation
15219     * 
15220     * @apiParam {String} token user's api token
15221     * 
15222     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/notice_to_user for credit card authentication
15223     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/close for Force Charge, Lite Credit Paid, Chocotto Monthly Payment, Chocotto Force Charge
15224     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/store/card_register_complete for Credit Card Change
15225     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/credit_retry_complete for Credit Card Retry
15226     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/close for Individual Corporate Standard, Premium, Light Membership
15227     * 
15228     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage for user not found
15229     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/payment/failure_settlement if on maintenance period
15230     * 
15231     * @apiSuccessExample Success Response If credit card authentication:
15232     * Redirects to {{ENV}}/mobapp/payment/notice_to_user
15233     * 
15234     * @apiSuccessExample Success Response If Force Charge, Lite Credit Paid, Chocotto Monthly Payment, Chocotto Force Charge:
15235     * Redirects to {{ENV}}/mobapp/close
15236     * 
15237     * @apiSuccessExample Success Response If Credit Card Change:
15238     * Redirects to {{ENV}}/mobapp/store/card_register_complete
15239     * 
15240     * @apiSuccessExample Success Response If Credit Card Retry:
15241     * Redirects to {{ENV}}/mobapp/payment/credit_retry_complete
15242     * 
15243     * @apiSuccessExample Success Response If Individual Corporate Standard, Premium, Light Membership:
15244     * Redirects to {{ENV}}/mobapp/close
15245     * 
15246     * @apiErrorExample Error Response If user not found:
15247     * Redirects to {{ENV}}/mobapp/retrypage
15248     * 
15249     * @apiErrorExample Error Response If on maintenance period:
15250     * Redirects to {{ENV}}/mobapp/payment/failure_settlement
15251     * 
15252     * @apiSampleRequest off
15253     */
15254    public function mobapp_credit_register_confirm() {
15255        $this->layout = 'mobapp';
15256        $formType = Configure::read('payment_credit_authentication');
15257        $userData = $this->mobappGetUserData(array('logFileName' => 'card_reregister', 'formType' => $formType)); // get user data and validate
15258        $apiToken = $this->request->query['token'];
15259
15260        // redirect to retry page if data does not exist or expired
15261        if (!$data = $this->memcache->get('mobappUserCreditRegisterInfo_'.$apiToken)) {
15262            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.myTools::getMobappToken($_GET));
15263        }
15264
15265        $readSkipConfirmation = true; // skip the confirmation page
15266
15267        if ($this->request->is('post') || $readSkipConfirmation) {
15268            // check if token matches token in session
15269            $checkToken = $this->checkTokenMobapp($apiToken, $data['cardToken'], 'card-register-');
15270
15271            // check if token is true
15272            if ($checkToken) {
15273                $this->Session->write('mobapp_show_welcome_back_modal',true);
15274                $this->zeus_card_process_mobapp(array(
15275                    'data' => $data,
15276                    'form_type' => $formType,
15277                    'referrer' =>  array('controller' => 'Payment', 'action' => 'mobapp_credit_register', '?' => array('token' => $apiToken)),
15278                    'api_token' => $apiToken,
15279                    'card_token' => $data['cardToken']
15280                ));
15281            }
15282        }
15283
15284        if (isset($data['ZPaymentFullLogs']['cardnumber']) && !empty($data['ZPaymentFullLogs']['cardnumber'])) {
15285            $this->set('cardNumber', end(str_split($data['ZPaymentFullLogs']['cardnumber'], 4)));
15286        } else {
15287            $this->getAndSetCardInfo($userData['User']);
15288        }
15289
15290        $this->set('title_for_layout', __d('register','無料トライアル'));
15291        $this->set('data', $data);
15292        $this->set('apiToken', $apiToken);
15293        $this->render(myTools::getDeviceUrl() . 'Payment/credit_register_confirm');
15294    }
15295    /**
15296     * @api {get} /mobapp/payment/paypal_payment_credit_register_confirm/:token mobapp_paypal_credit_register_confirm()
15297     * @apiName mobapp_paypal_credit_register_confirm
15298     * @apiGroup Payment
15299     * @apiDescription This endpoint is used to display the paypal credit card register confirmation page
15300     * 
15301     * @apiParam {String} token user's api token
15302     * 
15303     * @apiSuccess {View} Render Renders the paypal credit card register confirmation page
15304     * 
15305     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if data does not exist or expired
15306     * 
15307     * @apiSuccessExample Success Response:
15308     * Render the paypal credit card register confirmation page
15309     * 
15310     * @apiErrorExample Error Response:
15311     * Redirects to {{ENV}}/mobapp/retrypage
15312     * 
15313     * @apiSampleRequest off
15314     */
15315    public function mobapp_paypal_credit_register_confirm() {
15316        $this->layout = 'mobapp';
15317        $logFileName = 'paypal_debug';
15318
15319        // get user data and validate
15320        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => Configure::read('payment_credit_authentication')));
15321        $apiToken = $this->request->query['token'];
15322
15323        // redirect to retry page if data does not exist or expired
15324        if (!$data = $this->memcache->get('mobappPaypalPaymentCreditRegisterData_' . $apiToken)) {
15325            $this->log(__METHOD__ . ' credit register data does not exist or expired. user api token --> ' . json_encode($apiToken), $logFileName);
15326            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage' . myTools::getMobappToken($_GET));
15327        }
15328
15329        // set payment gateway type
15330        $this->memcache->set(array(
15331            'key' => 'mobappCreditReregisterPaymentGatewayType_' . $apiToken,
15332            'value' => $data['payment_gateway_type'],
15333            'expire' => 3600 // 1 hour
15334        ));
15335
15336        $this->set('title_for_layout', __d('register','無料トライアル'));
15337        $this->set('paypalFlg', true); // use for modal loader
15338        $this->set('userApiToken', $apiToken);
15339        $this->render(myTools::getDeviceUrl() . 'Payment/paypal_credit_register_confirm');
15340    }
15341    /**
15342     * @api {get} /mobapp/payment/paypal_payment_credit_register_process/:token/:negativeTesting mobapp_paypal_credit_register_process()
15343     * @apiName mobapp_paypal_credit_register_process
15344     * @apiGroup Payment
15345     * @apiDescription This endpoint is used to process the paypal credit card register
15346     * 
15347     * @apiParam {String} token user's api token
15348     * @apiParam {String} negativeTesting negative testing flag 1 = true, 0 = false
15349     * 
15350     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/notice_to_user if success
15351     * 
15352     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if data does not exist or expired
15353     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/payment/credit_register if negative testing
15354     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if light plan data does not exist
15355     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if chocotto plan data does not exist
15356     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/payment/credit_register if paypal settlement fails
15357     * 
15358     * @apiSuccessExample Success Response:
15359     * Redirects to {{ENV}}/mobapp/payment/notice_to_user
15360     * 
15361     * @apiErrorExample Error Response If data does not exist or expired:
15362     * Redirects to {{ENV}}/mobapp/retrypage
15363     * 
15364     * @apiErrorExample Error Response If negative testing:
15365     * Redirects to {{ENV}}/mobapp/payment/credit_register
15366     * 
15367     * @apiErrorExample Error Response If light plan data does not exist:
15368     * Redirects to {{ENV}}/mobapp/retrypage
15369     * 
15370     * @apiErrorExample Error Response If chocotto plan data does not exist:
15371     * Redirects to {{ENV}}/mobapp/retrypage
15372     * 
15373     * @apiErrorExample Error Response If paypal settlement fails:
15374     * Redirects to {{ENV}}/mobapp/payment/credit_register
15375     * 
15376     * @apiSampleRequest off
15377     */
15378    public function mobapp_paypal_credit_register_process() {
15379        $this->autoRender = false;
15380        $this->layout = false;
15381        $logFileName = 'paypal_debug';
15382
15383        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => Configure::read('payment_credit_authentication')));
15384        $get = $this->request->query;
15385        $apiToken = $get['token'];
15386        $memKey = 'mobappPaypalPaymentCreditRegisterData_' . $apiToken;
15387
15388        //- NJ-27262 clear from landing page
15389        $this->Cookie->delete('chocotto_lp');
15390
15391        // negative testing
15392        if (isset($get['negativeTesting']) && $get['negativeTesting']) {
15393            // set the memcache error
15394            $this->memcache->set(array(
15395                'key' => 'card-error-'.$apiToken,
15396                'value' => __("Error : 決済失敗"),
15397                'expire' => 3600 // 1 hour
15398            ));
15399
15400            $memKey = 'paypalBillingAgreementData_' . $apiToken;
15401
15402            // delete memcache billing agreement data
15403            if ($this->memcache->get($memKey)) {
15404                $this->memcache->delete($memKey);
15405            }
15406
15407            return $this->redirect(myTools::getUrl() . "/mobapp/payment/credit_register?token=" . $apiToken);
15408        }
15409
15410        // redirect to retry page if data does not exist or expired
15411        if (!$data = $this->memcache->get($memKey)) {
15412            $this->log(__METHOD__ . ' credit register data does not exist or expired. user api token --> ' . json_encode($apiToken), $logFileName);
15413            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage' . myTools::getMobappToken($_GET));
15414        }
15415
15416        $data['formType'] = Configure::read('payment_credit_authentication');
15417
15418        $userTable = new UserTable($userData['User']);
15419        $membershipTypes = UserTable::getEngMembershipTypeData();
15420        $membershipTypeIndex = $userTable->getMembershipTypeIndex();
15421
15422        // - NJ-18780 : init var
15423        $paymentPlanType = (isset($get['payment_plan_type']) && $get['payment_plan_type'] ) ? $get['payment_plan_type'] : 0;
15424
15425
15426        $userData['User']['statusBefore'] = $membershipTypes[$membershipTypeIndex];
15427        $userData['User']['statusAfter'] = $membershipTypes[2];
15428
15429        if ($paymentPlanType == Configure::read('register_plan_types.light')) {
15430            
15431            // - fetch the lite payment plan 
15432            $litefreeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
15433                'currencyCode' => $userData['User']['currency_code'],
15434                'paymentPlanId' => Configure::read('payment_plans.light_plan_free'),
15435                'logFileName' => 'card_reregister'
15436            ));
15437
15438            if (!$litefreeTrialData) {
15439
15440                // delete memcache paypal payment credit register data
15441                $this->memcache->delete($memKey);
15442
15443                $this->log(__METHOD__ . ' payment plan data does not exist or expired. user api token --> ' . json_encode($apiToken), $logFileName);
15444                return $this->redirect(myTools::getUrl() . '/mobapp/retrypage' . myTools::getMobappToken($_GET));
15445            }
15446
15447            // - update the light price id 
15448            $lightPlanPriceId = $litefreeTrialData['priceId'];
15449
15450            // - NJ-18780 : set  light free membership type 
15451            $normalLightFreeMemtype = Configure::read('membership_type_lightplan_free');
15452
15453            $user['statusAfter'] = $membershipTypes[$normalLightFreeMemtype];// update the status after to lite plan free
15454
15455            // - set update data 
15456            $data['paymentPlanData'] = $litefreeTrialData;// set to update the plan use
15457
15458            // update the form type 
15459            $data['formType'] = myTools::getLitePlanUserFormType(Configure::read('payment_plans.light_plan_free'));
15460
15461        // if annual discount option
15462        } elseif ($paymentPlanType == Configure::read('register_plan_types.premium_with_annual_discount_option')) {
15463            $annualDiscountOptionData = $this->DiscountOptionsPrice->getPaymentData(['currencyCode' => $userData['User']['currency_code'], 'discountOptionId' => Configure::read('discount_option.annual.plan_id')]);
15464
15465            // redirect to credit page if annual discount option does not exist or is not enabled
15466            if (!$annualDiscountOptionData) {
15467                return $this->redirect('/');
15468            }
15469
15470            // change amount to 0 since this is a subscription
15471            $annualDiscountOptionData['amount'] = 0;
15472
15473            // update payment transaction (add annual discount option data)
15474            $this->PaymentTransaction->updatePaymentParams(array('paymentHash' => $data['ZPaymentFullLogs']['paymentHash'], 'updateData' => ['annualDiscountOption' => $annualDiscountOptionData]));
15475
15476            $data['discountOption'] = $annualDiscountOptionData;
15477
15478        //- NJ-27262 : new chocotto plan
15479        } elseif ($paymentPlanType == Configure::read('register_plan_types.chocotto')) {
15480            
15481            // - fetch the chocotto payment plan 
15482            $chocottofreeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
15483                'currencyCode' => $userData['User']['currency_code'],
15484                'paymentPlanId' => Configure::read('payment_plans.free_trial_chocotto'),
15485                'logFileName' => 'card_reregister'
15486            ));
15487
15488            if (!$chocottofreeTrialData) {
15489
15490                // delete memcache paypal payment credit register data
15491                $this->memcache->delete($memKey);
15492
15493                $this->log(__METHOD__ . ' payment plan data does not exist or expired. user api token --> ' . json_encode($apiToken), $logFileName);
15494                return $this->redirect(myTools::getUrl() . '/mobapp/retrypage' . myTools::getMobappToken($_GET));
15495            }
15496
15497            // - update the light price id 
15498            $chocottoPlanPriceId = $chocottofreeTrialData['priceId'];
15499
15500            // - NJ-27262 : set  chocotto free membership type 
15501            $chocottoFreeMemtype = Configure::read('membership_type_chocotto_plan_free');
15502
15503            $user['statusAfter'] = $membershipTypes[$chocottoFreeMemtype];// update the status after to chocotto plan free
15504
15505            // - set update data 
15506            $data['paymentPlanData'] = $chocottofreeTrialData;// set to update the plan use
15507
15508            // update the form type 
15509            $data['formType'] = myTools::getChocottoPlanUserFormType(Configure::read('payment_plans.free_trial_chocotto'));
15510        }
15511
15512        $this->Session->write('mobapp_show_welcome_back_modal',true);
15513
15514        // process paypal settlement
15515        $result = $this->paypalSaveBillingAgreement($data, $userData['User']);
15516
15517        // delete memcache paypal payment credit register data
15518        $this->memcache->delete($memKey);
15519
15520        // redirect to reregister page if result is false
15521        if (!$result['success']) {
15522            // set the memcache error
15523            $this->memcache->set(array(
15524                'key' => 'card-error-'.$apiToken,
15525                'value' => __("Error : 決済失敗"),
15526                'expire' => 3600 // 1 hour
15527            ));
15528
15529            $memKey = 'paypalBillingAgreementData_' . $apiToken;
15530
15531            // delete memcache billing agreement data
15532            if ($this->memcache->get($memKey)) {
15533                $this->memcache->delete($memKey);
15534            }
15535
15536            $result['status'] = 0;
15537
15538            // update payment transaction
15539            $this->PaymentTransaction->paypalUpdatePaymentTransaction($result);
15540            return $this->redirect(myTools::getUrl() . "/mobapp/payment/credit_register?token=" . $apiToken);
15541        }
15542
15543        // send registration completion email
15544        App::uses('myMailer','Lib');
15545        $mailId = Configure::read('site_in_mail.student_registration_complete');
15546        myMailer::sendTemplateMail($mailId, $userData['User']['email'], $userData['User'], array(), 'User');
15547
15548        $memKey = 'mobappCreditReregisterPaymentGatewayType_' . $apiToken;
15549
15550        // delete memcache payment gateway type
15551        if ($this->memcache->get($memKey)) {
15552            $this->memcache->delete($memKey);
15553        }
15554
15555        // redirect to notice to user page
15556        $this->Session->write('reenroll_native_option', true);
15557        return $this->redirect(array('controller' => 'Payment', 'action' => 'mobapp_credit_register_notice_to_user', '?' => array('token' => $apiToken)));
15558    }
15559
15560    /**
15561     * @api {get} /mobapp/payment/notice_to_user/:token/:cardType mobapp_credit_register_notice_to_user()
15562     * @apiName mobapp_credit_register_notice_to_user
15563     * @apiGroup Payment
15564     * @apiDescription This endpoint is used to display the notice to user page
15565     * 
15566     * @apiParam {String} token user's api token
15567     * @apiParam {String} cardType user's card type
15568     * 
15569     * @apiSuccess {View} Render Renders the notice_to_user page
15570     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/close for Chocotto Plan
15571     * 
15572     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage for user not found / amount does not exist / complimentary code does not exist
15573     * 
15574     * @apiSuccessExample Success Response:
15575     * Renders the notice_to_user page
15576     * 
15577     * @apiSuccessExample Success Response If Chocotto Plan:
15578     * Redirects to {{ENV}}/mobapp/clos
15579     * 
15580     * @apiErrorExample Error Response If user not found / amount does not exist / complimentary code does not exist:
15581     * Redirects to {{ENV}}/mobapp/retrypage
15582     * 
15583     * @apiSampleRequest off
15584     */
15585    public function mobapp_credit_register_notice_to_user(){
15586        $this->layout = 'mobapp';
15587        $urlParams = myTools::getMobappToken($_GET);
15588
15589        // redirect to retry page if param token is not set
15590        if (!isset($this->request->query['token']) || empty($this->request->query['token'])) {
15591            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
15592        }
15593
15594        // get api token
15595        $apiToken = $this->request->query['token']; 
15596        $userParams = array(
15597            'fields' => array(
15598                'User.id',
15599                'User.currency_code',
15600                'User.card_company',
15601                'User.timezone_id',
15602                'User.next_charge_date',
15603                'User.complimentary_code',
15604                'User.payment_plan_id',
15605                'User.native_language2'
15606        ),
15607            'apiToken' => $apiToken
15608        );
15609
15610        // redirect to retry page if user does not exist
15611        if (!$userData = $this->User->getWPMobappUserData($userParams)) {
15612            $this->log(__METHOD__ . ' User api token does not exist. User params --> ' . json_encode($userParams), $logFileName);
15613            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.myTools::getMobappToken($_GET));
15614        }
15615
15616        //- chocotto plan
15617        if (in_array(
15618            $userData['User']['payment_plan_id'],
15619            [
15620                Configure::read('payment_plans.free_trial_chocotto'),
15621                Configure::read('payment_plans.chocotto_plan')
15622            ]
15623        )) {
15624            return $this->redirect('/mobapp/close'.myTools::getMobappToken($_GET)."&type=chocotto");
15625        }
15626
15627        // get monthly price
15628        $amount = $this->PaymentPlanPrice->getMonthlyPrice(array(
15629            'currencyCode' => $userData['User']['currency_code'],
15630            'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
15631            'numberFormatFlg' => true
15632        ));
15633
15634        // redirect to retry page if amount does not exist
15635        if (!isset($amount)) {
15636            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.myTools::getMobappToken($_GET));
15637        }
15638
15639        // if not paypal user
15640        if ($userData['User']['card_company'] != Configure::read('card_company.paypal')) {
15641            // read cache card token
15642            $cacheCardToken = $this->memcache->get('card-register-'.$apiToken);
15643            $cardToken = isset($this->request->query['cardToken']) ? $this->request->query['cardToken'] : null;
15644
15645            if ((!$cacheCardToken || !$cardToken) && ($cacheCardToken !== $cardToken) && !isset($this->request->query['wp'])) {
15646                //set error
15647                $this->memcache->set(array(
15648                    'key' => 'card-error-'.$apiToken,
15649                    'value' => 'ERROR : Card validation token mismatch.',
15650                    'expire' => 3600
15651                    ));
15652                //redirect to select credit cards
15653                return $this->redirect(array(
15654                    'controller' => 'Payment',
15655                    'action' => 'mobapp_credit_register',
15656                    '?' => array('token' => $apiToken)
15657                    ));
15658            }
15659
15660            $this->memcache->delete('card-register-'.$apiToken);
15661        }
15662
15663        //get device platform
15664        $platform = myTools::mobappDetectPlatform();
15665
15666        //update user platform
15667        $this->User->updateUserPlatform($userData['User']['id'], $platform);
15668        
15669        //NJ-13482 Rerenced from notice_to_user::notice_to_user
15670        $userCurrencycode = isset($userData['User']['currency_code']) ? $userData['User']['currency_code'] : Configure::read('default.currency_code');
15671        $monthlyPrice = $this->PaymentPlanPrice->getMonthlyPrice(array(
15672            'currencyCode' => $userCurrencycode,
15673            'paymentPlanId' => Configure::read('payment_plans.premium_plan')
15674        ));
15675
15676        $currencyData = ClassRegistry::init('Currency')->getSymbolAndPosition($userCurrencycode);
15677        $monthlyPriceSymbol =  myTools::getCurrencySymbol($userCurrencycode);
15678        $this->set('monthlyPrice', myTools::addPriceSymbol(myTools::formatAmount($monthlyPrice), $currencyData['symbol'], $currencyData['prefix_suffix_flg']));
15679        $this->set('monthlyPriceSymbol', $monthlyPriceSymbol);
15680
15681        $_timeDiff = $this->Timezone->getTimeDiff(
15682            array(
15683                'id' => $userData['User']['timezone_id']
15684            )
15685        );
15686        $timeDiff = $_timeDiff * 60;
15687        $nextSettlementDate = '';
15688
15689        if(!empty($userData['User']['next_charge_date']) && $userData['User']['next_charge_date'] != 0) {
15690            $date = date('Y-m-d H:59', strtotime($userData['User']['next_charge_date'] . '-1 hour'));
15691        } else {
15692            $date = $this->User->getFirstNextChargeDate();
15693            if($userData['User']['card_company'] == Configure::read('card_company.zeus')) {
15694                $date = date('Y-m-d H:i:s', strtotime($date . '-1 minute'));
15695            } else {
15696                $date = date('Y-m-d ', strtotime($date)) . date('H:59');
15697            }
15698        }
15699
15700        // NC-7459
15701        if (
15702            $userData['User']['complimentary_code']
15703            && isset($userData['User']['payment_plan_id'])
15704            && $userData['User']['payment_plan_id'] != Configure::read('payment_plans.free_trial') // except if user is registering to free trial from complimentary
15705        ) { // @NOTE double check
15706            $ccData = $this->ComplimentaryCode->useReplica()->find('first', array(
15707            'fields' => array('available_days'),
15708            'conditions' => array('code' => $userData['User']['complimentary_code'])
15709            ));
15710
15711            if (!$ccData) {
15712                $this->log(__METHOD__.' complimentary code does not exist.' . json_encode($userData), 'card_registration');
15713                return $this->redirect(myTools::getUrl().'/mobapp/retrypage'.myTools::getMobappToken($_GET));
15714            }
15715            $availableDays = $ccData['ComplimentaryCode']['available_days'] ? $ccData['ComplimentaryCode']['available_days'] - 1 : 0;
15716            $date = date('Y-m-d H:i:s', strtotime('+'.$availableDays.' days'));
15717        }
15718        // convert to user time
15719        $userDate = TimezoneTable::computeTimeToUser(array(
15720            'time' => strtotime($date),
15721            'timestamp' => $timeDiff,
15722            'format' => 'Y-m-d H:i:s'
15723        ));
15724
15725        $weekdate = date('w', strtotime($userDate));
15726        if ($userData['User']['complimentary_code']) {
15727            $time = date('23:59', strtotime($userDate));
15728        } else {
15729            $time = date('H:i', strtotime($userDate));
15730        }
15731
15732
15733        $year = date('Y', strtotime($userDate));
15734        $month = $userData['User']['native_language2'] == 'en' ? date('M', strtotime($userDate)) : date('m', strtotime($userDate));
15735        $day = date('d', strtotime($userDate));
15736
15737        if ( in_array($userData['User']['native_language2'], Configure::read('main_supported_language')) ) {
15738
15739            if ($userData['User']['native_language2'] != Configure::read('default.user_language') ) {
15740                if ($userData['User']['native_language2'] == 'en') {
15741                    $format = 'm d, Y';
15742                } else {
15743                    $format = __d('account','Y年m月d日');
15744                }
15745            } else {
15746                $format = 'Y 年 m 月 d 日';
15747            }
15748
15749            $pattern = array();
15750            $replace = array();
15751
15752            $pattern[0] = '/Y/';
15753            $pattern[1] = '/m/';
15754            $pattern[2] = '/d/';
15755
15756            $replace[0] = $year;
15757            $replace[1] = $month;
15758            $replace[2] = $day;
15759
15760
15761            $nextSettlementDate = preg_replace($pattern, $replace, $format);
15762
15763        } else {
15764            $nextSettlementDate = date('F j, Y', strtotime($userDate));
15765        }
15766
15767        
15768        if (!$this->globalLanguage && $userData['User']['native_language2'] != 'en') {
15769            $week = array(__dx('account','week',"日"), __dx('account','week',"月"), __dx('account','week',"火"), __dx('account','week',"水"), __dx('account','week',"木"), __dx('account','week',"金"), __dx('account','week',"土"));
15770            $nextSettlementDate .= ' ('.$week[$weekdate].')';
15771        }
15772
15773        $userInfo = $this->User->getUserDataByApiToken($apiToken);
15774        $userId = $userInfo['User']['id'];
15775
15776        // - get bonus coins on registration
15777        $receiveBonus = UsersPointTable::checkIfUserReceiveBonusUponRegister($userId);
15778        if (!$receiveBonus && empty($userInfo['User']['complimentary_code'])) {
15779            UsersPointTable::giveBonusCoins(['userId' => $userId, 'triggerNo' => 1]);
15780        }
15781
15782        # NJ-18780 - lite plan native option setting ->
15783        $settingName = Configure::read('setting_names.native_plan_display_setting');
15784        $settingData = ClassRegistry::init('SettingOption')->getOptions($settingName);
15785
15786        $userObj = new UserTable($userInfo);
15787        $userMemberShipTypeIndexInt = $userObj->getMembershipTypeIndex();
15788
15789        $continueURL = '/mobapp/payment/native_plan'.myTools::getMobappToken($_GET);
15790
15791        if(empty($userData['User']['corporate_id']) && empty($userData['User']['studysapuri_id']) && !empty($settingData)) {
15792            if (isset($settingData['display_on_membership']) && !in_array($userMemberShipTypeIndexInt, $settingData['display_on_membership']) ||
15793                (isset($settingData['display_currency_codes']) && !in_array($userObj->currency_code, $settingData['display_currency_codes']))
15794            ) {
15795                $continueURL = '/mobapp/close'.myTools::getMobappToken($_GET)."&type=sign_up";
15796            }
15797        }
15798
15799        $this->set('continueTo', $continueURL);
15800        # NJ-18780 - lite native option setting  <-
15801
15802        //set variable
15803        $this->set('apiToken', $apiToken);
15804        $this->set('amount', $amount);
15805        $this->set('nextSettlementDate', $nextSettlementDate. ' ' . $time);
15806        $this->set('userLanguage', isset($userData['User']['native_language2']) ? $userData['User']['native_language2'] : Configure::read('default.user_language'));
15807        $this->render(myTools::getDeviceUrl() . 'Payment/notice_to_user');
15808    }
15809
15810    /**
15811     * @api {get} /mobapp/payment/native_plan/:token mobapp_credit_register_native_plan()
15812     * @apiName mobapp_credit_register_native_plan
15813     * @apiGroup Payment
15814     * @apiDescription This endpoint is used to display the native plan page
15815     * 
15816     * @apiParam {String} token user's api token
15817     * 
15818     * @apiSuccess {View} Render Renders the native_plan page
15819     * 
15820     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/close for user not found
15821     * 
15822     * @apiSuccessExample Success Response:
15823     * Renders the native_plan page
15824     * 
15825     * @apiErrorExample Error Response If user not found:
15826     * Redirects to {{ENV}}/mobapp/close
15827     * 
15828     * @apiSampleRequest off
15829     */
15830    public function mobapp_credit_register_native_plan() {
15831
15832        $checkSessionWelcomeModal = $this->Session->read('mobapp_show_welcome_back_modal');
15833        if ($checkSessionWelcomeModal) {
15834            $this->Session->delete('mobapp_show_welcome_back_modal');
15835        }
15836
15837        $this->set('checkSessionWelcomeModal',$checkSessionWelcomeModal);
15838
15839        $this->layout = 'mobapp';
15840        $token = !empty($this->request->query['token']) ? $this->request->query['token'] : "";
15841        $userInfo = ClassRegistry::init("User")->find("first", array("conditions" => array("User.api_token"=> $token), 'recursive' => -1));
15842        $userData = new UserTable($userInfo["User"]);
15843
15844        if (time() < strtotime(Configure::read('native_option_cashback_campaign.period.end'))) {
15845            $isCashBackCampaign = true;
15846        } else {
15847            $isCashBackCampaign = false;
15848        }
15849        
15850        $monthlyPriceSymbol =  myTools::getCurrencySymbol($userData->currency_code);
15851        $getNativeOptionPaymentCharge = $this->NativeOption->getNativeOptionPaymentCharge(
15852            array(
15853                'daily_calculation' => true,
15854                'half_price' => $isCashBackCampaign,
15855                'user_id' => $userData->id,
15856            )   
15857        );
15858        $pData = $getNativeOptionPaymentCharge;
15859        $optionData = $pData['native_option_data'];
15860        $amount = isset($optionData['amount']) ? myTools::formatAmount($optionData['amount']) : 0;
15861        $symbol = isset($optionData['symbol']) ? $optionData['symbol'] : '';
15862        $monthly_price = isset($pData['monthly_price']) ? myTools::formatAmount($pData['monthly_price']) : 0;
15863        $num1 = str_replace(',', '', $monthly_price);
15864        $num2 = str_replace(',', '', $amount);
15865        $total = $num1 + $num2;
15866        $formatTotal = 0;
15867        if (!empty(strpos($total, "."))) {
15868            $formatTotal = number_format($total, 2);
15869        } else {
15870            $formatTotal = number_format($total);
15871        }
15872
15873
15874        // -----  NJ-23812 start support for native plan charge --------
15875        $request_data = $this->request->query;
15876        $unli_option_type = isset($request_data['unli_option']) ? $request_data['unli_option'] : Configure::read('native_speaker.options.all_you_can_eat');
15877
15878        $optionAmount = 0;
15879        $initialAmount = 0;
15880        $nativeOptionName = '';
15881        $currencySymbol = '';
15882        $prefix_suffix_flg = '';
15883        $logFileName = 'native_option_debug';
15884        $currency = $this->currency;
15885        
15886
15887        if ($userData) {
15888            // - ini reason
15889            $reason = 2;
15890
15891            //If user membership type is invalid
15892            if (!in_array($userData->getMembershipTypeIndex(), Configure::read('native_speaker.valid_memberships')) && !in_array($userData->getMembershipTypeIndex(), Configure::read('corporate_company_payment.native_option_allowed_user'))){
15893                   if (isset($userData->payment_plan_id)) {
15894                        $corpType = myTools::getCoporateTypeUsingPaymentPlanId($userData->payment_plan_id);
15895                        // light or limited
15896                        if (in_array($corpType, array(3,4))) {
15897                            $reason = 4;
15898                        } else {
15899                            $reason = 3;
15900                        }
15901                    }
15902                    return $this->redirect(myTools::getUrl() . '/mobapp/close' . myTools::getMobappToken($_GET)).'&type=sign_up';
15903            }
15904
15905            $registerOption = $this->Session->read('reenroll_native_option') ? 1 : 0;
15906
15907        }
15908
15909
15910        if($unli_option_type == Configure::read('native_speaker.options.all_you_can_eat')) {
15911            if (time() < strtotime(Configure::read('native_option_cashback_campaign.period.end'))) {
15912                $isCashBackCampaign = true;
15913            } else {
15914                $isCashBackCampaign = false;
15915            }
15916            $getNativeOptionPaymentCharge = $this->NativeOption->getNativeOptionPaymentCharge(
15917                array(
15918                    'daily_calculation' => true,
15919                    'half_price' => $isCashBackCampaign,
15920                    'user_id' => $userData->id,
15921                    'option_type' => Configure::read('native_speaker.options.all_you_can_eat')
15922                )   
15923            );
15924            if ($getNativeOptionPaymentCharge) {
15925                if (!$this->User->ifNativeOptionAvailable($getNativeOptionPaymentCharge['native_option_data']['limit'])) {
15926                    $this->log(__METHOD__ . ' native option limit exceeded.', $logFileName);
15927                    return $this->redirect(myTools::getUrl() . '/mobapp/option/start_disabled'.myTools::getMobappToken($_GET));
15928                }
15929                $this->set('nativeOptionPaymentChargeData', $getNativeOptionPaymentCharge);
15930            }
15931
15932            $initialAmount = $getNativeOptionPaymentCharge['native_option_data']['initial_amount'];
15933            $price_with_coupon = $getNativeOptionPaymentCharge['price_with_coupon'];
15934        }
15935
15936        # NJ-18780 : lite plan native plan
15937        $showLightPlanModal = false;
15938        if (in_array($userData->payment_plan_id, Configure::read('lite_payment_plans'))) {
15939            $showLightPlanModal = true;
15940        }
15941
15942        $this->set('showLightPlanModal', $showLightPlanModal);
15943
15944        $this->set('unli_option_type', $unli_option_type);
15945        $this->set('rt_ck', $this->Cookie->read('rt_ck'));
15946        $this->set('currency', $currency);
15947        $this->set('nativeOptionName', $nativeOptionName);
15948        $this->set('amount', number_format($optionAmount));
15949        $this->set('initialAmount', $initialAmount);
15950        $this->set('currencySymbol', $currencySymbol);
15951        $this->set('prefixSuffixFlg', $prefix_suffix_flg);
15952        $this->set('token', $token);
15953
15954        // -----  NJ-23812 end support for native plan charge --------
15955
15956        $this->set('monthlyPrice', $monthly_price);
15957        $this->set('nativeOption', $amount);
15958        $this->set('symbol', $monthlyPriceSymbol);
15959        $this->set('total', $formatTotal);
15960        $this->set('title_for_layout', __d('register','7日間無料トライアル'));
15961        $this->set('headtext', __d('register','7日間無料トライアル'));
15962        $this->render(myTools::getDeviceUrl() . 'Payment/native_plan');
15963    }
15964
15965    /**
15966     * @api {get} /mobapp/payment/credit_register_questionaire/:token mobapp_credit_register_questionnaire()
15967     * @apiName mobapp_credit_register_questionnaire
15968     * @apiGroup Payment
15969     * @apiDescription This endpoint is used to redirect to the questionnaire page.
15970     * 
15971     * @apiParam {String} token The user's token
15972     * 
15973     * @apiSuccess {View} Redirect to {{ENV}}/mobapp/register/questionnaire/:token
15974     * 
15975     * @apiError {View} Redirect to {{ENV}}/mobapp/retrypage if the token is empty or does not exist.
15976     * 
15977     * @apiSuccessExample Success Response:
15978     * Redirect to {{ENV}}/mobapp/register/questionnaire/:token
15979     * 
15980     * @apiErrorExample Error Response:
15981     * Redirect to {{ENV}}/mobapp/retrypage
15982     * 
15983     * @apiSampleRequest off
15984     */
15985    public function mobapp_credit_register_questionnaire(){
15986        return $this->redirect(myTools::getUrl() . '/mobapp/register/questionnaire'.myTools::getMobappToken($_GET)); 
15987    }
15988
15989    /**
15990     * @api {get} /mobapp/payment/wp_credit/:token mobapp_wp_credit()
15991     * @apiName mobapp_wp_credit
15992     * @apiGroup Payment
15993     * @apiDescription This endpoint is used to display the credit card registration page for WP users.
15994     * 
15995     * @apiParam {String} token The user's token
15996     * 
15997     * @apiSuccess {View} Redirect to {{ENV}}/mobapp/payment/wp_credit_register/:token if
15998     * 
15999     * @apiError {View} Redirect to {{ENV}}/mobapp/retrypage if the token is empty or does not exist.
16000     * 
16001     * @apiSuccessExample Success Response:
16002     * Redirect to {{ENV}}/mobapp/payment/wp_credit_register/:token
16003     * 
16004     * @apiErrorExample Error Response:
16005     * Redirect to {{ENV}}/mobapp/retrypage
16006     * 
16007     * @apiSampleRequest off
16008     */
16009    public function mobapp_wp_credit() {
16010        $this->blockWithdrawnSapuriToS('mobapp');
16011        $this->disablePageForSapuri('mobapp');
16012        $this->layout = "mobapp";
16013        $urlParams = myTools::getMobappToken($_GET);
16014        $logFileName = 'card_registration';
16015        $formType = Configure::read('payment_credit_authentication');
16016        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType));
16017        $userData = $userData['User'];
16018        // redirect to retry page if empty token
16019        if (!isset($this->request->query['token']) || empty($this->request->query['token'])) {
16020            $this->log(
16021                __METHOD__ . ' Query string parameter token does not exist. Parameter(s) --> ' . json_encode($this->request->query) . " | " . json_encode($_SERVER['REQUEST_URI']), 
16022                $logFileName
16023            );
16024            return $this->redirect(myTools::getUrl().'/mobapp/retrypage'.myTools::getMobappToken($_GET));
16025        }
16026
16027        //NJ-13482 Skip Step Re-enrollment
16028        if (isset($userData['id']) && $this->isForTrialReenrollment($userData['id'])) {
16029            return $this->redirect(myTools::getUrl() . '/mobapp/payment/wp_credit_register'.$urlParams);
16030        }
16031        // store to memcached variable
16032        $this->memcache->set(array(
16033            'key' => 'ifUserFromWPPaymentCredit_' . $this->request->query['token'],
16034            'value' => true,
16035            'expire' => 86400
16036        ));
16037
16038        // get api token
16039        $apiToken = $this->request->query['token'];
16040        $isTokenExist = $this->User->find('count', array(
16041            'conditions' => array('api_token' => $apiToken),
16042            'recursive' => -1
16043        ));
16044
16045        // redirect to retry page if api token not exist
16046        if (!$isTokenExist) {
16047            $this->log(__METHOD__ . ' User api token does not exist. api token --> ' . json_encode($apiToken), $logFileName);
16048            return $this->redirect(myTools::getUrl().'/mobapp/retrypage'.myTools::getMobappToken($_GET));
16049        }
16050
16051        // get error from memcache
16052        $error = $this->memcache->get('card_regist_error_'.$apiToken);
16053
16054        // check if there is error
16055        if ($error) {
16056            $this->memcache->delete('card_regist_error_'.$apiToken);
16057            $this->set('error', $error);
16058        }
16059
16060        $this->response->disableCache();
16061        
16062        $this->PhoneVerifyCheckLog->openDBReplica();
16063        $isSMSAuth = $this->PhoneVerifyCheckLog->find('count',array(
16064            'conditions' => array(
16065                'status' => 0,
16066                'user_id' => $userData['id']
16067            ),
16068            'fields' => array(
16069                'phone_number'
16070            ),
16071            'recursive' => -1
16072        ));
16073        $this->PhoneVerifyCheckLog->closeDBReplica();
16074
16075        if ($isSMSAuth || 
16076            $userData['facebook_id'] ||
16077            $userData['google_id'] ||
16078            $userData['line_id'] ||
16079            $userData['apple_id'] ||
16080            $userData['sms_through_flg'] ||
16081            $userData['reason_id']
16082        ) {
16083            $creditRegisterCacheData = array(
16084                'key' => 'success-auth'.$apiToken,
16085                'value' => true,
16086                'expire' => 86400
16087            );
16088            $this->memcache->set($creditRegisterCacheData);
16089        }
16090
16091        $_timeDiff = $this->Timezone->getTimeDiff(
16092            array(
16093                'id' => $this->userData['timezone_id']
16094            )
16095        );
16096        $timeDiff = $_timeDiff * 60;
16097        $date = $this->User->getFirstNextChargeDate();
16098        $time = date('H:59');
16099        $date = date('Y-m-d', strtotime($date)). ' '.$time;
16100
16101        // convert to user time
16102        $userDate = TimezoneTable::computeTimeToUser(array(
16103            'time' => strtotime($date),
16104            'timestamp' => $timeDiff,
16105            'format' => 'Y-m-d'
16106        ));
16107
16108        $this->set('limitFreePeriodGlobal', $userDate);
16109
16110        $this->set('apiToken', $apiToken);
16111        // NC-6879 2020 NEw year campaign
16112        $registrationBonusCoin = Configure::read('credit.bonus_coin_authentication');
16113        $this->set('registrationBonusCoin',  $registrationBonusCoin);
16114        $this->render(myTools::getDeviceUrl() . 'Payment/wp_credit');
16115    }
16116
16117    /**
16118     * @api {post} /mobapp/payment/wp_credit_register/:token mobapp_wp_credit_register()
16119     * @apiName mobapp_wp_credit_register
16120     * @apiGroup Payment
16121     * @apiDescription This endpoint is used to process the credit card registration for WP users.
16122     * 
16123     * @apiParam {String} token The user's token
16124     * 
16125     * @apiBody {Number} cardType The card type (0 = existing card, 1 = new card)
16126     * 
16127     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/wp_credit_register_form/:token if cardType is 1.
16128     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/wp_credit_register_confirm?token=:token if cardType is 0.
16129     * 
16130     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/sms_authentication if the user is not authenticated.
16131     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage amount does not exist / token is invalid.
16132     * 
16133     * @apiExample Example usage:
16134     * {
16135     *         "cardType": 1
16136     * }
16137     * 
16138     * @apiSuccessExample Success Response New Card:
16139     * Redirect to {{ENV}}/mobapp/payment/wp_credit_register_form/:token
16140     * 
16141     * @apiSuccessExample Success Response Existing Card:
16142     * Redirect to {{ENV}}/mobapp/payment/wp_credit_register_confirm?token=:token
16143     * 
16144     * @apiErrorExample Error Response Not Authenticated:
16145     * Redirect to {{ENV}}/mobapp/sms_authentication
16146     * 
16147     * @apiErrorExample Error Response Amount does not exist / token is invalid:
16148     * Redirect to {{ENV}}/mobapp/retrypage 
16149     * 
16150     * @apiSampleRequest off
16151     */
16152    public function mobapp_wp_credit_register() {
16153        $this->blockWithdrawnSapuriToS('mobapp');
16154        $this->disablePageForSapuri('mobapp');
16155        // set variables
16156        $urlParams = myTools::getMobappToken($_GET);
16157        $logFileName = 'card_reregister';
16158        $formType = Configure::read('payment_credit_authentication');
16159        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType));
16160        $user = new UserTable($userData['User']);
16161        $memberType = $user->getUserMembership();
16162        $userData = $userData['User'];
16163        $this->layout = "mobapp";
16164        $this->response->disableCache();
16165        $apiToken = $userData['api_token'];
16166        $currencyCode = $userData['currency_code'];
16167        $memKey = "credit_reregister_{$userData['id']}_{$currencyCode}";
16168        $cardType = $this->memcache->get($memKey);
16169        $cardType = isset($cardType) ? $cardType : 0;
16170
16171        // get monthly price
16172        $amount = $this->PaymentPlanPrice->getMonthlyPrice(array(
16173            'currencyCode' => $currencyCode,
16174            'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
16175            'logFileName' => $logFileName,
16176            'numberFormatFlg' => true
16177        ));
16178        $isCardRegistered = (!empty($userData['card_brand']) && !empty($userData['card_number'])) ? true : false;
16179
16180        if (!isset($amount)) {
16181            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
16182        }
16183
16184        if ($this->request->is('post')) {
16185            $cardType = $this->request->data['cardType'];
16186
16187            // memcache card type value
16188            $this->memcacheCardType(array(
16189                'key' => $memKey,
16190                'value' => $cardType
16191            ));
16192
16193            // redirect to hosted page if using new card ($cardType = 1)
16194            if ($cardType) {
16195                 $this->redirect(myTools::getUrl() . "/mobapp/payment/wp_credit_register_form".$urlParams);
16196            // redirect to confirm page if using existing card ($cardType = 0)
16197            } else {
16198                $this->redirect(myTools::getUrl() . "/mobapp/payment/wp_credit_register_confirm?token=$apiToken");
16199            }
16200        }
16201
16202        // if has complimentary code
16203        if (isset($userData['complimentary_code']) && $userData['complimentary_code']) {
16204            $this->set('cPlan', true);
16205        }
16206
16207        // check if there is error
16208        if ($error = $this->memcache->get('card_register_error_'.$apiToken)) {
16209            $this->memcache->delete('card_register_error_'.$apiToken);
16210            $this->set('error', $error);
16211        }
16212        
16213        // - NJ-23812: display premium data 
16214        $premiumData = $this->PaymentPlanPrice->getPaymentData(array(
16215            'currencyCode' => $currencyCode,
16216            'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
16217            'logFileName' => 'card_reregister'
16218        ));
16219        $currencyData = $this->Currency->getSymbolAndPosition($currencyCode);
16220        
16221        $this->set('monthlyPrice', myTools::formatAmount($premiumData['amount']));
16222        $this->set('monthylyPriceNoTax', myTools::formatAmount($premiumData['amountConstTaxDeducted']));
16223        $this->set('monthlyPriceSymbol',myTools::getCurrencySymbol($currencyCode));
16224
16225
16226        // set view variables
16227        $this->set('cardLogo', myTools::getWorldpayCardLogo($userData['card_brand']));
16228        $this->set('cardBrand', $userData['card_brand']);
16229        $this->set('cardNumber', $userData['card_number']);
16230
16231        $this->set('cardType', $cardType);
16232        $this->set('apiToken', $apiToken);
16233        $this->set('user', $userData);
16234        $this->set('amount', $amount);
16235        
16236        // check if allowed aftee
16237        $this->checkAfteeSupported($userData);
16238
16239        $this->set('title_for_layout', __d('register','7日間無料トライアル'));
16240
16241
16242        // check if allowed aftee
16243        $enableAftee = isset($userData['native_language2']) && $userData['native_language2'] == 'zh-tw' ? 1 : 0;
16244        if (isset($userData['currency_code']) && $userData['currency_code'] != 'TWD') {
16245            $enableAftee = 0;
16246        }
16247
16248        $useAftee = ($enableAftee && $memberType == 'free_user') ? 1 : 0;
16249        $this->set('useAftee', false);
16250
16251        $this->set('enableAftee', false);
16252
16253        // set view variables
16254        $this->set('pmtValue', 'auth');
16255        $this->set('logFileName', $logFileName);
16256        $this->set('worldpayFlg', true);            
16257        $this->set('memKeyError', 'card_register_error_'.$apiToken);
16258        $this->set('referrer', urlencode(myTools::getUrl()."/mobapp/payment/wp_credit_register?token={$apiToken}"));
16259        $this->set('successUrl', urlencode(myTools::getUrl()."/mobapp/payment/notice_to_user?token={$apiToken}&wp=true"));
16260        $this->set('formType', $formType);
16261        $this->set('isCardRegistered',$isCardRegistered);
16262
16263        $this->render(myTools::getDeviceUrl() . 'Payment/wp_credit_register_form');
16264    }
16265
16266    /**
16267     * @api {get} /mobapp/payment/wp_credit_register_form/:token mobapp_wp_credit_register_form()
16268     * @apiName mobapp_wp_credit_register_form
16269     * @apiGroup Payment
16270     * @apiDescription This endpoint is used to display the credit card registration form for WP users.
16271     * 
16272     * @apiParam {String} token The user's token
16273     * 
16274     * @apiSuccess {View} Render Displays the credit card registration form.
16275     * 
16276     * @apiError {View} Redirect to {{ENV}}/mobapp/retrypage if the token is empty or does not exist.
16277     * 
16278     * @apiSuccessExample Success Response:
16279     * Displays the credit card registration form.
16280     * 
16281     * @apiErrorExample Error Response:
16282     * Redirect to {{ENV}}/mobapp/retrypage
16283     * 
16284     * @apiSampleRequest off
16285     */
16286    public function mobapp_wp_credit_register_form() {
16287        $this->blockWithdrawnSapuriToS('mobapp');
16288        $this->disablePageForSapuri('mobapp');
16289        // set variables
16290        $logFileName = 'card_reregister';
16291        $formType = Configure::read('payment_credit_authentication');
16292        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType));
16293        $apiToken = $userData['User']['api_token'];
16294        $this->layout = "mobapp";
16295        $this->response->disableCache();
16296
16297        $isCardRegistered = (!empty($userData['card_brand']) && !empty($userData['card_number'])) ? true : false;
16298
16299        //NJ-23812 :  get monthly price
16300        $amount = $this->PaymentPlanPrice->getMonthlyPrice(array(
16301            'currencyCode' => $currencyCode,
16302            'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
16303            'logFileName' => $logFileName,
16304            'numberFormatFlg' => true
16305        ));
16306
16307
16308        // check if allowed aftee
16309        $this->checkAfteeSupported($userData['User']);
16310
16311        // NJ=23812: set view vars
16312        $this->set('amount', $amount);
16313        $this->set('isCardRegistered', $isCardRegistered);
16314
16315        // set view vars
16316        $this->set('pmtValue', 'auth');
16317        $this->set('apiToken', $apiToken);
16318        $this->set('logFileName', $logFileName);
16319        $this->set('worldpayFlg', true);
16320        $this->set('memKeyError', 'card_register_error_'.$apiToken);
16321        $this->set('referrer', urlencode(myTools::getUrl()."/mobapp/payment/wp_credit_register?token={$apiToken}"));
16322        $this->set('successUrl', urlencode(myTools::getUrl()."/mobapp/payment/notice_to_user?token={$apiToken}&wp=true"));
16323        $this->set('formType', $formType);
16324        $this->set('title_for_layout', '再入会');
16325        $this->render(myTools::getDeviceUrl() . 'Payment/wp_credit_register_form');
16326    }
16327    /**
16328     * @api {post} /mobapp/payment/wp_credit_register_confirm/:token mobapp_wp_credit_register_confirm()
16329     * @apiName mobapp_wp_credit_register_confirm
16330     * @apiGroup Payment
16331     * @apiDescription This endpoint is used to process the credit card registration confirmation for WP users.
16332     * 
16333     * @apiParam {String} token The user's token
16334     * 
16335     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/notice_to_user?token={$apiToken}&wp=true if the payment transaction is successful.
16336     * 
16337     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if the token is empty or does not exist.
16338     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/payment/wp_credit_register?token= with error message if the payment transaction is unsuccessful.
16339     * 
16340     * @apiSuccessExample Success Response:
16341     * Redirect to {{ENV}}/mobapp/payment/notice_to_user?token={$apiToken}&wp=true
16342     * 
16343     * @apiErrorExample Error Response No token:
16344     * Redirect to {{ENV}}/mobapp/retrypage
16345     * 
16346     * @apiErrorExample Error Response Payment Transaction Unsuccessful:
16347     * Redirect to {{ENV}}/mobapp/payment/wp_credit_register?token= with error message
16348     */
16349    public function mobapp_wp_credit_register_confirm() {
16350        // set variables
16351        $logFileName = 'card_reregister';
16352        $formType = Configure::read('payment_credit_authentication');
16353        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType));
16354        $this->layout = "mobapp";
16355        $this->response->disableCache();
16356        $userData = $userData['User'];
16357        $currencyCode = $userData['currency_code'];
16358        $userId = $userData['id'];
16359        $apiToken = $userData['api_token'];
16360        $memKey = "credit_reregister_{$userId}_{$currencyCode}";
16361        $urlParams = myTools::getMobappToken($_GET);
16362
16363        $readSkipConfirmation = true;//NJ-23812:skip the confirmation page
16364
16365        if ($this->request->is('post') || $readSkipConfirmation) {
16366            $paymentMethodType = myTools::getWPPaymentMethodType($userData['card_brand'], 'auth');
16367            $merchantCode = myTools::getWPMerchantCode($paymentMethodType);
16368            $paymentMethod = explode('_', $paymentMethodType);
16369            $paymentMethod = isset($paymentMethod[0]) ? $paymentMethod[0] : null;
16370            $orderCode = myTools::generateOrderCode($userId);
16371            $currencyExponents = Configure::read('worldpay.currency_exponents');
16372            $exponent = $currencyExponents[$currencyCode];
16373            $nominalAmountArr = myTools::getWorldpayNominalAmountList($paymentMethod, $merchantCode);
16374
16375            // get nominal amount with checking currency exponent
16376            $totalAmountArr = myTools::wpGetAmount($exponent, $nominalAmountArr[$currencyCode]);
16377            $ncAmount = $totalAmountArr['ncAmount'];
16378            $wpAmount = $totalAmountArr['wpAmount'];
16379
16380            // get free trial payment data
16381            $freeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
16382                'currencyCode' => $currencyCode,
16383                'paymentPlanId' => Configure::read('payment_plans.free_trial'),
16384                'logFileName' => $logFileName
16385            ));
16386
16387            if (!$freeTrialData) {
16388                return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
16389            }
16390
16391            $userData['payment_plan_id'] = $freeTrialData['paymentPlanId'];
16392            $userData['price_id'] = $freeTrialData['priceId'];
16393
16394            $wpData = array(
16395                'cardToken' => $userData['card_token'],
16396                'merchantCode' => $merchantCode,
16397                'paymentHash' => $orderCode,
16398                'wpPaymentAmount' => $wpAmount
16399            );
16400
16401            // set payment amount
16402            $userData['paymentAmount'] = 0;
16403
16404            // create payment transaction
16405            if (!$pt = $this->createPaymentTransaction($formType, $userData, $wpData)) {
16406                $this->log(__METHOD__ .' Failed to save payment transaction. Params --> ' . json_encode($wpData), $logFileName);
16407                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to save payment transaction. Params --> ' . json_encode($wpData), 'error');
16408                return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
16409            }
16410
16411            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - After save payment transaction. Params --> ' . json_encode($wpData), 'error');
16412
16413            // if aftee payment
16414            if (
16415                $userData['card_company'] == Configure::read('card_company.aftee') ||
16416                ($userData['card_brand'] == "AFTEE" && !empty($userData['aftee_transaction_identifier']))
16417            ) {
16418
16419                // default result
16420                $checkRes = array(
16421                    'OrderCode' => $orderCode,
16422                    'authentication_token' => $userData['card_token'],
16423                    'response' => 'Aftee payment amount is zero',
16424                    'customer' => array(
16425                        'phone_number' =>  $userData['phone_number']
16426                    )
16427                );
16428                $receivableResult = json_encode($checkRes);
16429                $afteeTransactionIdentifier = $userData['aftee_transaction_identifier'];
16430
16431    
16432                if ($userData['paymentAmount'] > 0) {
16433
16434                    if (!class_exists('AfteePaymentService')) {
16435                        App::uses('AfteePaymentService','Lib');
16436                    }
16437                    $afteeService = new AfteePaymentService();
16438                    $afteeChecksumData = array(
16439                        'shopItemId' => "AFTEE" . $formType,
16440                        'itemName' => 'CreditRegisterUsingExistingCard',
16441                        'itemPrice' => $userData['paymentAmount'],
16442                        'itemCount' => 1,
16443                        'customerPhoneNumber' => $userData['phone_number'],
16444                        'customerEmail' => $userData['email'],
16445                        'shopTransactionNo' => $orderCode,
16446                        'userID' =>  $userData['id']
16447                    );
16448                    $checksum = $afteeService->generateChecksum($afteeChecksumData, false);
16449                    $afteeData = array(
16450                        'authentication_token' => $userData['card_token'],
16451                        'related_id' => $userData['aftee_transaction_identifier'],
16452                        'checksum' => $checksum['checksum'],
16453                        'shop_transaction_no' => $orderCode,
16454                        'transaction_options' => array(1)
16455                    );
16456            
16457                    $afteePaymentData = array_merge($afteeData, $checksum['settlementData']);
16458        
16459                    // aftee execute payment
16460                    $receivableResult = $afteeService->directPayment($afteePaymentData);
16461                    $checkRes = json_decode($receivableResult, true);
16462
16463
16464                    if ( isset($checkRes['object']) && $checkRes['object'] == 'transaction') {
16465                        $prPaymentSuccess = true;
16466                    } else if ( !array_key_exists("object", $checkRes) || (isset($checkRes['object']) && $checkRes['object'] == 'error')) {
16467                        $prPaymentSuccess = false;
16468                    }
16469
16470                    $afteeTransactionIdentifier = isset($checkRes['id']) && !empty($checkRes['id']) ? $checkRes['id'] : NULL;
16471                    if (isset($checkRes['related_transaction']) && !empty($checkRes['related_transaction'])) {
16472                        $afteeTransactionIdentifier = $checkRes['related_transaction'];
16473                    }
16474                    $orderCode = isset($checkRes['shop_transaction_no']) && !empty($checkRes['shop_transaction_no']) ? $checkRes['shop_transaction_no'] : NULL;
16475                    $checkRes['OrderCode'] = $orderCode;
16476                }
16477
16478
16479                // process payment data
16480                if ($prPaymentSuccess || $userData['paymentAmount'] == 0) {
16481                    // set user model
16482                    $uModel = $this->User;
16483                    $dataSource = $uModel->getDataSource();
16484                    $dataSource->begin();
16485
16486                    $afteeParams = array(
16487                        'data' => $checkRes,
16488                        'ptData' => $pt,
16489                        'logFileName' => $logFileName,
16490                        'dataSource' => $dataSource,
16491                        'amount' => $userData['paymentAmount'],
16492                        'userData' => $userData,
16493                        'transactionIdentifier' => $afteeTransactionIdentifier,
16494                        'aftee' => 1
16495                    );
16496
16497    
16498                    $this->processAfteePayment($afteeParams);
16499                }
16500
16501                // update payment transaction
16502                $updateData = array(
16503                    'id' => $pt['id'],
16504                    'fields' => array(
16505                        'status' => $prPaymentSuccess,
16506                        'response_text' => array('aftee_directPayment_response' => $receivableResult))
16507                );
16508
16509                // update payment transaction
16510                $this->PaymentTransaction->updateAfteePaymentTransaction($updateData);
16511
16512
16513                // redirect to payment_credit_charge with error display if direct payment response is not authorised
16514                if (!$prPaymentSuccess && $userData['paymentAmount'] > 0) {
16515                    if (!class_exists('myMemcached')) {
16516                        App::uses('myMemcached', 'Lib');
16517                    }
16518                    $memKeyError = 'card_register_error_' . $apiToken;
16519                    $memerror = __('トランザクションを完了できません。 もう一度お試しください。');
16520                    $memcached = new myMemcached();
16521                    $memcached->set(array(
16522                        'key' => $memKeyError,
16523                        'value' => $memerror,
16524                        'expire' => 3600 // 1 hour
16525                    ));
16526                    return $this->redirect(myTools::getUrl() . '/mobapp/payment/wp_credit_register?token='.$apiToken);
16527                }
16528                // default worldpay
16529            } else {
16530
16531                $wpData = array(
16532                    'merchantCode' => $merchantCode,
16533                    'orderCode' => $orderCode,
16534                    'description' => 'Credit Register Using Existing Card',
16535                    'currencyCode' => $currencyCode,
16536                    'exponent' => $exponent,
16537                    'amount' => $wpAmount,
16538                    'cardToken' => $userData['card_token'],
16539                    'email' => $userData['email'],
16540                    'authenticatedShopperId' => $userId,
16541                    'xmlName' => 'direct_payment_with_token',
16542                    'shopperIpAddress' => $_SERVER["REMOTE_ADDR"],
16543                    'wpTransactionIdentifier' => $userData['wp_transaction_identifier'],
16544                    'paymentMethod' => $paymentMethod
16545                );
16546
16547                $result = wpPaymentService::directPayment($wpData);
16548
16549                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - directPayment result --> ' . json_encode($result), 'error');
16550
16551                $updateData = array(
16552                    'id' => $pt['id'],
16553                    'fields' => array('response_text' => array('directPayment_response' => $result)),
16554                    'logFileName' => $logFileName
16555                );
16556
16557                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - before updatePaymentTransaction result --> ' . json_encode($updateData), 'error');
16558
16559                // redirect to retry page if failed to update payment transaction
16560                if (!$this->updatePaymentTransaction($updateData)) {
16561                    return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
16562                }
16563
16564                // redirect to wp_credit_register with error display if direct payment response is not authorised
16565                if (!myTools::checkIfWPPaymentResponseIsAuthorised($result)) {
16566                    $params = array(
16567                        'apiToken' => $apiToken,
16568                        'wpResponse' => $result,
16569                        'memKey' => 'card_register_error_' . $apiToken
16570                    );
16571                    myTools::parseAndSetWPErrorResponse($params);
16572                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - WP Payment not authorised --> ' . json_encode($params), 'error');
16573                    return $this->redirect(myTools::getUrl() . '/mobapp/payment/wp_credit_register?token='.$apiToken);
16574                }
16575            }
16576
16577            // delete memcache
16578            if ($this->memcache->get($memKey)) {
16579                $this->memcache->delete($memKey);
16580            }
16581            // send registration completion email
16582            App::uses('myMailer','Lib');
16583            $mail_id = Configure::read('site_in_mail.student_registration_complete');
16584            if ($userData &&  !in_array($userData['currency_code'], Configure::read('global_free_trail_currencies') ) ) {
16585                $mail_id = Configure::read('site_in_mail.registration_no_trial_currencies');
16586            }
16587
16588            myMailer::sendTemplateMail($mail_id, $userData['email'], $userData, array(), 'User');
16589
16590            $stepKey = Configure::read('registration_steps.credit_card_registration_success');
16591            $this->saveStep($userId, $stepKey);
16592
16593            $this->Session->write('reenroll_native_option', true);
16594            return $this->redirect(myTools::getUrl() . "/mobapp/payment/notice_to_user?token={$apiToken}&wp=true");
16595        }
16596
16597        // set view variables
16598        $this->set('title_for_layout', __d('register','無料トライアル'));
16599        $this->set('cardLogo', myTools::getWorldpayCardLogo($userData['card_brand']));
16600        $this->set('apiToken', $apiToken);
16601        $this->set('cardBrand', $userData['card_brand']);
16602        $this->set('cardNumber', $userData['card_number']);
16603        $this->render(myTools::getDeviceUrl() . 'Payment/wp_credit_register_confirm');
16604    }
16605
16606    /**
16607     * @api {get} /mobapp/payment/credit_charge/:token mobapp_credit_charge()
16608     * @apiName mobapp_credit_charge
16609     * @apiGroup Payment
16610     * @apiDescription this endpoint is used to process the credit card charge for mobapp users.
16611     * 
16612     * @apiParam {String} token The user's token
16613     * 
16614     * @apiSuccess {View} Render Displays the credit card charge form.
16615     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/close if user has already paid.
16616     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/wp_credit_charge if the user's currency is not JPY.
16617     * @apiSuccess {View} Redirect Redirects to {{ENV}}//mobapp/payment/credit_charge_form if the user is temporary and does not have a card number.
16618     * 
16619     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if the token is empty or does not exist.
16620     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage If the user is a paid member or a Chocotto camp paid member and not on a complimentary plan.
16621     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage If the premium payment plan is not supported.
16622     * @apiError {View} Redirect Redirects to {{{ENV}}}/mobapp/retrypage If the corporate payment plan data is not supported
16623     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if the payment transaction creation fails.
16624     * 
16625     * @apiSuccessExample Success Response:
16626     * Displays the credit card charge form.
16627     * 
16628     * @apiSuccessExample Success Response User Already Paid:
16629     * Redirect to {{ENV}}/mobapp/close
16630     * 
16631     * @apiSuccessExample Success Response Currency Not JPY:
16632     * Redirect to {{ENV}}/mobapp/payment/wp_credit_charge
16633     * 
16634     * @apiSuccessExample Success Response Temporary User:
16635     * Redirect to {{ENV}}//mobapp/payment/credit_charge_form
16636     * 
16637     * @apiErrorExample Error Response No Token:
16638     * Redirect to {{ENV}}/mobapp/retrypage
16639     * 
16640     * @apiErrorExample Error Response User is Paid Member or Chocotto Camp Paid Member and Not on Complimentary Plan:
16641     * Redirect to {{ENV}}/mobapp/retrypage
16642     * 
16643     * @apiErrorExample Error Response Premium Payment Plan Not Supported:
16644     * Redirect to {{ENV}}/mobapp/retrypage
16645     * 
16646     * @apiErrorExample Error Response Corporate Payment Plan Data Not Supported:
16647     * Redirect to {{ENV}}/mobapp/retrypage
16648     * 
16649     * @apiErrorExample Error Response Payment Transaction Creation Failed:
16650     * Redirect to {{ENV}}/mobapp/retrypage
16651     * 
16652     * @apiSampleRequest off
16653     */
16654    public function mobapp_credit_charge() {
16655        if ($this->Session->read('mobapp_show_welcome_back_modal')){
16656            $this->Session->delete('mobapp_show_welcome_back_modal');
16657        }
16658
16659        $this->response->disableCache();
16660        $this->blockWithdrawnSapuriToS('mobapp');
16661        $this->disablePageForSapuri('mobapp');
16662        // set variables
16663        $this->layout = 'mobapp';
16664        $logFileName = 'card_charge';
16665        $urlParams = myTools::getMobappToken($_GET);
16666        $formType = Configure::read('payment_credit_force_charge');
16667        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType)); // get user data and validate
16668
16669        // NJ-30828: set view to display user's paypal email
16670        $this->setPaypalUser($userData);
16671
16672        // - check user if already paid
16673        $userDetails = new UserTable($userData['User']);
16674
16675        $creditChargePaymentSucessFlg = $this->memcache->get('creditChargePaymentSucess' . $userDetails->id);
16676        if($creditChargePaymentSucessFlg) {
16677            return $this->redirect(array('controller' => 'Mobapp', 'action' => 'close', '?' => array('token'=> $userDetails->api_token, 're_enrolled' => 1)));
16678        }
16679
16680        $memberType = $userDetails->getUserMembership();
16681        if(
16682            in_array(
16683                $memberType,
16684                [
16685                    Configure::read('user.member_type_paid'),
16686                    Configure::read('user.member_chocotto_camp_paid')
16687                ]
16688            ) &&
16689            $userDetails->payment_plan_id != Configure::read('payment_plans.complimentary_plan')
16690        ) {
16691            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
16692        }
16693
16694        $userData = $userData['User'];
16695        $_user = $userData;
16696        $enableChocottoPlan = true;
16697        $this->restrictForTrialNotConducted($userData, $urlParams);
16698        // redirect to worldpay if not zuespay user (currency != JPY)
16699        if ($userData['currency_code'] != Configure::read('currency_jpy')) {
16700            return $this->redirect(myTools::getUrl() . '/mobapp/payment/wp_credit_charge'.$urlParams);
16701        }
16702
16703        $isCompUser = (isset($userData['complimentary_code']) && $userData['complimentary_code']) ? true : false;
16704        $this->set('isCompUser',$isCompUser);
16705
16706        $this->setPerMonthSymbol($_user['native_language2'], true);
16707
16708        $trialNumber = 0;
16709        if(
16710            $isCompUser &&
16711            $memberType == Configure::read('user.member_type_paid') && 
16712            $userDetails->payment_plan_id == Configure::read('payment_plans.complimentary_plan')
16713        ) {
16714            $checkExpiry = $this->ComplimentaryCode->getCCLessonRemAndExpiryDate($userDetails);
16715            if (
16716                !empty($checkExpiry) &&
16717                $checkExpiry['templateType'] == 0 &&
16718                $checkExpiry['expiryDate'] >= date('Y-m-d H:i') &&
16719                $checkExpiry['lessonRem'] > 0
16720            ) {
16721                $trialNumber = 7;
16722            }
16723        }
16724
16725        $apiToken = $this->request->query['token'];
16726        $appVersion = $this->request->query['appVersion'];
16727        $deviceType = $this->request->query['deviceType'];
16728        $couponData = $this->Session->read('apply_coupon_usage_data');
16729        $isFreeFlg  = false;
16730        $freeNumber = 0;
16731        $monthlyFee = 0;
16732        $corporateIndiUser = false;
16733
16734        $this->set('appVersion', $appVersion);
16735        $this->set('deviceType', $deviceType);
16736
16737        // get premium plan data
16738        $ppData = $this->PaymentPlanPrice->getPaymentData(array(
16739            'currencyCode' => $userData['currency_code'],
16740            'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
16741            'logFileName' => $logFileName
16742        ));
16743
16744        // redirect to retry page if premium payment plan is not supported
16745        if (!$ppData) {
16746            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
16747        }
16748
16749        $corporateUser = isset($userData['corporate_id']) ? true : false;
16750
16751        $annualDiscountOptionData = $this->DiscountOptionsPrice->getPaymentData(['currencyCode' => $userData['currency_code'], 'discountOptionId' => Configure::read('discount_option.annual.plan_id')]);
16752        $annualDiscountOptionAmount = 0;
16753
16754        // - check if there is annual discount option data
16755        if ($annualDiscountOptionData) {
16756            $annualDiscountOptionAmount = myTools::formatAmount($annualDiscountOptionData['amount']);
16757        } 
16758
16759        $this->set('enableAnnualDiscountOption', $annualDiscountOptionData ? true : false);
16760        $this->set('annualDiscountOptionAmount', $annualDiscountOptionAmount);
16761
16762        // get corporate payment method
16763        $this->Corporate->openDBReplica();
16764        $corporateData = $this->Corporate->find('first', array(
16765            'fields' => array('payment_method'),
16766            'conditions' => array('id' => $userData['corporate_id']),
16767            'recursive' => -1
16768        ));
16769        $this->Corporate->closeDBReplica();
16770
16771        $corporateData = $corporateData ? $corporateData['Corporate'] : null;
16772
16773        // if corporate user
16774        if ($corporateUser && $corporateData && $corporateData['payment_method'] == 1) {
16775            // get corporate payment plan data
16776            $cpData = $this->getCorporatePaymentPlan($userData);
16777
16778            // redirect to retry page if not supported
16779            if (!$cpData) {
16780                return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
16781            }
16782
16783            $cfAmount = $cpData['fAmount'];
16784            $corporateIndiUser = $cpData['corporateIndiUser'];
16785        }
16786
16787        // delete old card charge token
16788        $this->memcache->delete('card-charge-'.$apiToken);
16789
16790        $cardToken = md5 (uniqid(rand(), true));
16791
16792        // save new card charge token to memcache
16793        $this->memcache->set(array(
16794            'key' => 'card-charge-'.$apiToken,
16795            'value' => $cardToken,
16796            'expire' => 3600
16797        ));
16798
16799        $corporateMemKey = 'mobappCreditChargeCorporateData_' . $userData['id'];
16800
16801        // delete if exist
16802        if ($this->memcache->get($corporateMemKey)) {
16803            $this->memcache->delete($corporateMemKey);
16804        }
16805
16806
16807        $cAmount = $lightTotalLessFee =  0;
16808        $corpType = myTools::getCoporateTypeUsingPaymentPlanId($userData['payment_plan_id']);
16809        if ($corporateIndiUser) {
16810            $corporateTaxRate = Configure::read('tax.increase');
16811            
16812            // light
16813            if ($corpType == Configure::read('corporate_type.light')) {
16814                $indiLightPlanUser = true;
16815                $getCorporateData = $this->Corporate->getCorporateLightUserMonthly(array('user_id' => $userData['id']));
16816                $paymentAmount = isset($getCorporateData['total']) ? $getCorporateData['total'] : 0;
16817                $basicFee = isset($getCorporateData['basic_fee']) ? $getCorporateData['basic_fee'] : 0;
16818                $lessonFee = isset($getCorporateData['lesson_fee']) ? $getCorporateData['lesson_fee'] : 0;
16819                $basicFeeWoTax = isset($getCorporateData['basic_fee_discounted']) ? $getCorporateData['basic_fee_discounted'] : 0;
16820                $freeNumber = isset($getCorporateData['fee_charge_count']) ? $getCorporateData['fee_charge_count'] : 0;
16821                $isFreeFlg = isset($getCorporateData['free_charge_flg']) ? $getCorporateData['free_charge_flg'] : false;
16822                $monthlyFee = isset($getCorporateData['monthly_fee_wo_tax']) ? $getCorporateData['monthly_fee_wo_tax'] : 0;
16823                $cfAmount = myTools::formatAmount($basicFeeWoTax);
16824                $lessonLimit = $this->Corporate->getLessonLimit($userData['corporate_id']);
16825                $cAmount = $basicFeeWoTax;
16826                $lightDiscount = isset($getCorporateData['discount']) ? $getCorporateData['discount'] : 0;
16827                $lightTotalLessFee = $monthlyFee + $lightDiscount;
16828
16829                $corporateMemData = array(
16830                    'lessonFee' => $lessonFee,
16831                    'basicFee' => $basicFee,
16832                    'freeFlg' => $isFreeFlg,
16833                    'freeNumber' => $freeNumber,
16834                    'monthlyFee' => $monthlyFee,
16835                    'fAmount' => $cfAmount,
16836                    'paymentAmount' => $paymentAmount * $corporateTaxRate,
16837                    'lessonLimit' => $lessonLimit,
16838                    'paymentPlanId' => $cpData['paymentPlanId'],
16839                    'priceId' => $cpData['priceId']
16840                );
16841            // standard or premium
16842            } elseif (in_array($corpType, array(Configure::read('corporate_type.premium'), Configure::read('corporate_type.standard')))) {
16843                $cdrParam = array('corporateId' => $userData['corporate_id'], 'corporateType' => $corpType);
16844                $discount = (int)$this->CorporateDiscountRate->getDiscount($cdrParam);
16845                $cAmount = $cpData['amount'] - $discount;
16846                $cfAmount = myTools::formatAmount($cAmount);
16847                $corporateMemData = array(
16848                    'cprAmount' => $cpData['amount'],
16849                    'cprDiscount' => $discount,
16850                    'paymentAmount' => $cAmount * $corporateTaxRate,
16851                    'fAmount' => $cfAmount,
16852                    'paymentPlanId' => $cpData['paymentPlanId'],
16853                    'priceId' => $cpData['priceId']
16854                );
16855            }
16856
16857            if (isset($corporateMemData)) {
16858                $this->memcache->set(array(
16859                    'key' => $corporateMemKey,
16860                    'value' => $corporateMemData,
16861                    'expire' => 3600 // 1 hr
16862                ));
16863            }
16864
16865            // if user is temporary redirect to form input after setting corporate memcached data needed later
16866            if ($userData['status'] == 0 && empty($user['card_number']) && empty($user['card_brand'])) {
16867
16868                $this->redirect(myTools::getUrl() . '/mobapp/register/corporate_creditform'.$urlParams); // New Corporate Users without Force to register a card
16869            }
16870        }
16871
16872        $userData = $this->changePaymentPlanIfTelecomUser($userData);
16873
16874        // get and delete errors
16875        if ($error = $this->memcache->get('card-error-'.$apiToken)) {
16876            $this->memcache->delete('card-error-'.$apiToken);
16877        }
16878
16879        // if complimentary plan
16880        if (isset($userData['com_plan_user']) && $userData['com_plan_user']) {
16881            $_cPlan = false;
16882
16883            // set com_plan_user to true if payment plan id is not null and is complimentary plan
16884            if (isset($userData['payment_plan_id']) && $userData['payment_plan_id'] == Configure::read('payment_plans.complimentary_plan')){
16885                $_cPlan = true;
16886            // set com_plan_user to true if payment plan id is null and is complimentary plan
16887            } elseif (!isset($userData['payment_plan_id']) && $this->Payment->ifComPlanUser($userData['id'])) {
16888                $_cPlan  = true;
16889            }
16890    
16891            $this->set('cPlan', $_cPlan);
16892        } else {
16893            // NC-3914
16894            $this->getAndSetCardInfo($userData);
16895        }
16896
16897        $isFamilyPlanBefore = PaymentTable::checkIfFamilyPlan(
16898            $userData['id'],
16899            $userData['hash16'],
16900            array(
16901                Configure::read('payment_credit_family_free'),
16902                Configure::read('payment_credit_family_monthly_payment')
16903            )
16904        );
16905
16906        $this->set('isFamilyPlanBefore', $isFamilyPlanBefore);
16907        $this->set('data', $this->memcache->get('mobappUserCreditChargeInfo_'.$apiToken));
16908
16909        $currencyCode = $userData['currency_code'];
16910        $pDataDisplay = $this->PaymentPlanPrice->getPaymentData(array(
16911            'currencyCode' => $currencyCode,
16912            'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
16913            'logFileName' => 'card_reregister'
16914        ));
16915
16916        $annualDiscountOption = $this->DiscountOptionsPrice->getPaymentData(['currencyCode' => $currencyCode, 'discountOptionId' => Configure::read('discount_option.annual.plan_id')]);
16917        $annualDiscountOptionAmount = $annualDiscountOption ? $annualDiscountOption['amount'] : 0;
16918
16919        // - check if there is annual discount option data
16920        if ($annualDiscountOption) {
16921            unset($annualDiscountOption['contract_start']);
16922            $annualDiscountOption += [
16923                'dosh_event' => Configure::read('discount_option.dosh_event.annual_discount'),
16924                'dosh_status' => Configure::read('discount_option.dosh_status.monthly_discount')
16925            ];
16926
16927            $annualDiscountOptionAmount = $annualDiscountOption['amount'];
16928        }
16929
16930        $monthlyPriceWithAnnualDiscount = $pDataDisplay['amount'] - $annualDiscountOptionAmount;
16931        $monthlyPriceWithAnnualDiscountNoTax = $monthlyPriceWithAnnualDiscount / Configure::read('added_tax_percentage');
16932        $monthlyPriceWithAnnualDiscountNoTax = round($monthlyPriceWithAnnualDiscountNoTax);
16933
16934        $this->set('enableAnnualDiscountOption', $annualDiscountOption ? true : false);
16935        $this->set('annualDiscountOptionAmount', myTools::formatAmount($annualDiscountOptionAmount));
16936        $this->set('monthlyPriceWithAnnualDiscount', myTools::formatAmount($monthlyPriceWithAnnualDiscount));
16937        $this->set('monthlyPriceWithAnnualDiscountNoTax', myTools::formatAmount($monthlyPriceWithAnnualDiscountNoTax));
16938
16939        // if corporate individual user
16940        if (isset($cpData)) {
16941            $this->set('cAmount',$cAmount);
16942            $this->set('cpFormatAmount', $cfAmount);
16943        }
16944
16945        $mobappCorpIndividualData = array(
16946            'apiToken' => $apiToken,
16947        );
16948        
16949        // data needed for corporate individual
16950        if ($corporateIndiUser) {
16951            $this->corpIndividualData($userData,$mobappCorpIndividualData);
16952        }
16953
16954        $currencyData = $this->Currency->getSymbolAndPosition($userData['currency_code']);
16955        $this->set('monthlyPrice', myTools::formatAmount($ppData['amount']));
16956        $this->set('monthylyPriceNoTax', myTools::formatAmount($ppData['amountConstTaxDeducted']));
16957        $this->set('monthlyPriceSymbol',myTools::getCurrencySymbol($userData['currency_code']));
16958        $this->set('lightTotalLessFee',$lightTotalLessFee);
16959
16960
16961        $this->setSupportPayPal($userData);
16962        $this->set('userData', $userData);
16963        $this->set('amount', $ppData['amount']);
16964        $this->set('ppFormatAmount', $ppData['fAmount']);
16965        $this->set('corporateIndiUser', $corporateIndiUser);
16966        $this->set('error', $error);
16967        $this->set('apiToken', $apiToken);
16968        $this->set('cardToken', $cardToken);
16969        $this->set('zeusTransactionFlag', true);
16970        $this->set('lessonLimit', isset($lessonLimit) ? $lessonLimit : 0);
16971        $this->set('indiLightPlanUser', isset($indiLightPlanUser) ? $indiLightPlanUser : false);
16972        $this->set('corporateType', $corpType);
16973        $this->set('isFreeFlg', $isFreeFlg);
16974        $this->set('freeNumber', $freeNumber);
16975        $this->set('monthlyFee', $monthlyFee);
16976        $this->set('corporateUser', $corporateUser);
16977        $this->set('paymentHash', '');
16978
16979        if ($trialNumber) {
16980            $this->set('title_for_layout', sprintf(__d('payment', '%s日間無料トライアル'), $trialNumber));
16981        } else {
16982            $this->set('title_for_layout', '再入会');
16983        }
16984
16985        $this->set('zeusCC', Configure::read('card_company.zeus'));
16986        $this->set('paypalCC', Configure::read('card_company.paypal'));
16987        $this->set('paypalUserData', $userData);
16988        $this->set('userApiToken', $apiToken);
16989        
16990        // NJ-23812 : redirect to credit charge form 
16991        $this->set('failURLReferer', myTools::getUrl() . "/mobapp/payment/credit_charge" . myTools::getMobappToken(array_merge(array('token' => $apiToken ), $_GET)) );
16992        $this->set('monthlyPriceSymbol', myTools::getCurrencySymbol($userData['currency_code']));
16993
16994        // NJ-32737
16995        $this->setCouponUseData($userData['id'], $userData['currency_code']);
16996
16997
16998            $this->set('paypalUserData', $userData);
16999            $this->set('userApiToken', $apiToken);
17000            // prepare the data if incase users using paypal payment method
17001            $data['paymentPlanData'] = $ppData;
17002            $data['receivablePayment'] = $this->PaymentReceivable->computeReceivableReservationPayment($userData['id']);
17003            $data['appreciationReceivable'] = $this->PaymentReceivable->computeReceivableReservationPayment($userData['id'], false, Configure::read('appreciation_data.payment_element_type'));
17004            $data['liveLessonReceivable'] = $this->PaymentReceivable->computeReceivableReservationPayment($userData['id'], false, Configure::read('payment_element_type.live'));
17005            $data['formType'] = $formType;
17006            $this->memcache->set(array(
17007                'key' => 'mobappPaypalPaymentCreditChargeData_' . $apiToken,
17008                'value' => $data,
17009                'expire' => 3600 // 1 hour
17010            ));
17011
17012            /**
17013             * Existing code for NJ-19183 displays the credit form in this page instead of /mobapp/payment/credit_charge_form
17014             * This is paymentHash support for NJ-2552 3D secure challenge
17015             * Goal: Prepopulate paymenthash value
17016             */
17017            $userDataArr = $userData;
17018            $paymentData = $ppData;
17019            $paymentPlanType = $data['ZPaymentFullLogs']['payment_plan_type'];
17020            // if retain indi plan
17021            if (!$corporateIndiUser) {                    
17022                $userDataArr['paymentAmount'] = $paymentData['amount'];
17023                $userDataArr['price_id'] = $paymentData['priceId'];
17024                $userDataArr['payment_plan_id'] = $paymentData['paymentPlanId'];
17025
17026                $data['ZPaymentFullLogs']['formType'] = $formType;
17027
17028                // add reserve payment receivable
17029                $userDataArr['paymentAmount'] +=  $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id']);
17030
17031                // add appreciation payment receivable
17032                $userDataArr['paymentAmount'] +=  $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('appreciation_data.payment_element_type'));
17033
17034                // add live lesson payment receivable
17035                $userDataArr['paymentAmount'] +=  $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('payment_element_type.live'));
17036                
17037                // add annual discount option
17038                if (
17039                    $annualDiscountOption &&
17040                    $paymentPlanType == Configure::read('register_plan_types.premium_with_annual_discount_option')
17041                ) {
17042                    $data['discountOption'] = $user['discountOption'] = $annualDiscountOptionData;
17043                }
17044
17045
17046
17047                $membershipStatusIndex = UserTable::getStudentMembershipStatus($userDataArr['id']);
17048                if (in_array($membershipStatusIndex, Configure::read('allow_coupon.settlement')) &&
17049                    isset($data['z_payment_form_type']) &&
17050                    in_array($data['z_payment_form_type'], Configure::read('allow_coupon.settlement_form_type'))
17051                ) {
17052                    if (isset($couponData['useCouponAmount']) && $couponData['useCouponAmount'] > 0) {
17053                        if ($data['ZPaymentFullLogs']['money'] >= $couponData['useCouponAmount']) {
17054                            $data['ZPaymentFullLogs']['money'] -= $couponData['useCouponAmount'];
17055                        } else {
17056                            $data['ZPaymentFullLogs']['money'] = 0;
17057                        }
17058
17059                        $userDataArr['couponUseSettlement'] = $couponData;
17060
17061                        // payment amount - coupon amount
17062                        $userDataArr['paymentAmount'] = $data['ZPaymentFullLogs']['money'];
17063
17064                    }
17065                }
17066
17067                if (!$pt = $this->createPaymentTransaction($formType, $userDataArr)) {
17068                    return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
17069                }
17070                $this->set('paymentHash', $pt['payment_hash']);
17071            }
17072            // redirect to retry page if failed to create payment transaction
17073            
17074            /**
17075             * NJ-19183 | NJ-25522 support end
17076             */
17077            $comp_plan_page = 'credit_charge';
17078            if ($isCompUser) {
17079                $comp_plan_page = "not_allowed_lite_plan_change";
17080                $ccData = $this->ComplimentaryCode->find('first', 
17081                    array(
17082                        'fields' => array('available_days','template_type '),
17083                        'conditions' => array(
17084                            'code' => $_user['complimentary_code'],
17085                            'template_type !=' => 0
17086                        )
17087                ));
17088
17089                if ($ccData) {
17090                    $comp_plan_page = 'credit_charge';
17091                }
17092            }
17093
17094            // NJ-18780 : set view support for lite plan
17095            $this->setLitePaymentInfoView($_user,false,false,$comp_plan_page);
17096
17097        #chocotto plan data
17098        $chocottoPlanData = $this->PaymentPlanPrice->getPaymentData(array(
17099            'currencyCode' => $_user['currency_code'],
17100            'paymentPlanId' => Configure::read('payment_plans.chocotto_plan'),
17101            'logFileName' => $logFileName ?? 'card_reregister'
17102        ));
17103
17104        // - set chocotto plan price
17105        $this->set('chocottoMonthlyPrice',$chocottoPlanData['fAmount']);
17106        $this->set('chocottoMonthlyPriceNoTax', myTools::formatAmount($chocottoPlanData['amountConstTaxDeducted']));            
17107
17108            $this->render(myTools::getDeviceUrl().'Payment/credit_charge_form');
17109    }
17110
17111    /**
17112     * @api {post} /mobapp/payment/credit_charge_form/:token/:cardToken mobapp_credit_charge_form()
17113     * @apiName mobapp_credit_charge_form
17114     * @apiGroup Payment
17115     * @apiDescription This endpoint is used to display and process the credit card charge form for mobapp users.
17116     * 
17117     * @apiParam {String} token The user's token
17118     * @apiParam {String} cardToken The card token
17119     * 
17120     * @apiBody {String} token The user's token.
17121     * @apiBody {String} cardToken The card token.
17122     * @apiBody {Object} ZPaymentFullLogs The payment logs object.
17123     * @apiBody {String} ZPaymentFullLogs.payment_plan_type The payment plan type.
17124     * @apiBody {String} ZPaymentFullLogs.paymentHash The payment hash.
17125     * @apiBody {Number} ZPaymentFullLogs.money The payment amount.
17126     * @apiBody {String} ZPaymentFullLogs.formType The form type.
17127     * @apiBody {String} ZPaymentFullLogs.telno The default telephone number.
17128     * @apiBody {String} ZPaymentFullLogs.clientip The client IP address.
17129     * @apiBody {Number} ZPaymentFullLogs.indiCorpType The individual corporate type.
17130     * @apiBody {String} [ZPaymentFullLogs.corporatePlan] The corporate plan type 
17131     * @apiBody {Object} [discountOption] The discount option data .
17132     * @apiBody {String} [discountOption.dosh_event] The discount event.
17133     * @apiBody {String} [discountOption.dosh_status] The discount status.
17134     * @apiBody {Number} [discountOption.amount] The discount amount.
17135     * @apiBody {Object} [paymentPlanData] The payment plan data . This is required if user is paypal user.
17136     * @apiBody {Number} [paymentPlanData.amount] The payment amount.
17137     * @apiBody {Number} [paymentPlanData.fAmount] The formatted payment amount.
17138     * @apiBody {Number} [paymentPlanData.priceId ]The price ID.
17139     * @apiBody {Number} [paymentPlanData.paymentPlanId] The payment plan ID.
17140     * @apiBody {Number} receivablePayment The receivable payment amount 
17141     * @apiBody {Number} appreciationReceivable The appreciation receivable amount 
17142     * @apiBody {Number} liveLessonReceivable The live lesson receivable amount 
17143     * @apiBody {String} userApiToken The user's API token (optional).
17144     * @apiBody {Object} [userData] The user data (optional).
17145     * @apiBody {Number} [userData.id] The user ID.
17146     * @apiBody {String} [userData.currency_code] The user's currency code.
17147     * @apiBody {Number} [userData.payment_plan_id] The user's payment plan ID.
17148     * @apiBody {Number} [userData.price_id] The user's price ID.
17149     * @apiBody {Number} [userData.paymentAmount] The user's payment amount.
17150     * @apiBody {Number} [userData.corporate_id] The user's corporate ID.
17151     * @apiBody {Number} [userData.lesson_fee] The user's lesson fee.
17152     * @apiBody {Number} [userData.basic_fee] The user's basic fee.
17153     * @apiBody {Number} [userData.cprAmount] The corporate receivable amount.
17154     * @apiBody {Number} [userData.cprDiscount] The corporate receivable discount.
17155     * @apiBody {String} [userData.corporateSettlementType] The corporate settlement type.
17156     * @apiBody {String} [userData.statusAfter] The user's status after payment.
17157     * @apiBody {String} [userData.statusBefore] The user's status before payment.
17158     * @apiBody {Object} [couponUseSettlement] The coupon use settlement data .
17159     * @apiBody {Number} [couponUseSettlement.useCouponAmount] The coupon use amount.
17160     * 
17161     * @apiSuccess {View} Render Displays the credit card charge form.
17162     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/paypal_payment_credit_charge_confirm?token={{token}} if the user is using PayPal.
17163     * @apiSuccess {View} Redirect Redirects to {{ENV}}/payment/mobapp_credit_charge_confirm if the form submission is successful.
17164     * 
17165     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if the token is empty or does not exist.
17166     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if the premium payment plan data is not supported.
17167     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if the corporate payment plan data is not supported.
17168     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if the payment transaction creation fails.
17169     * 
17170     * @apiExample Example usage:
17171     * {
17172     *         "token": "user_token",
17173     *       "cardToken": "card_token",
17174     *       "ZPaymentFullLogs": {
17175     *             "payment_plan_type": "premium",
17176     *             "paymentHash": "hash_value",
17177     *             "money": 1000,
17178     *             "formType": "force_charge",
17179     *             "telno": "1234567890",
17180     *             "clientip": "192.168.1.1",
17181     *             "indiCorpType": 1,
17182     *       },
17183     *      "receivablePayment": 100,
17184     *       "appreciationReceivable": 50,
17185     *       "liveLessonReceivable": 30,
17186     *       "userApiToken": "user_api_token"
17187     * }
17188     * 
17189     * @apiSuccessExample Success Response:
17190     * Display the credit card charge form.
17191     * 
17192     * @apiSuccessExample Success Response User is using PayPal:
17193     * Redirects to {{ENV}}/mobapp/payment/paypal_payment_credit_charge_confirm?token={{token}}
17194     * 
17195     * @apiSuccessExample Success Response Form submission is successful:
17196     * Redirects to {{ENV}}/payment/mobapp_credit_charge_confirm
17197     * 
17198     * @apiErrorExample Error Response Token is empty or does not exist:
17199     * Redirects to {{ENV}}/mobapp/retrypage
17200     * 
17201     * @apiErrorExample Error Response Premium payment plan data is not supported:
17202     * Redirects to {{ENV}}/mobapp/retrypage
17203     * 
17204     * @apiErrorExample Error Response Corporate payment plan data is not supported:
17205     * Redirects to {{ENV}}/mobapp/retrypage
17206     * 
17207     * @apiErrorExample Error Response Payment transaction creation fails:
17208     * Redirects to {{ENV}}/mobapp/retrypage
17209     * 
17210     * @apiSampleRequest off
17211     */
17212    public function mobapp_credit_charge_form(){
17213        $this->blockWithdrawnSapuriToS('mobapp');
17214        $this->disablePageForSapuri('mobapp');
17215        $this->layout = 'mobapp';
17216        $this->response->disableCache();
17217        $urlParams = myTools::getMobappToken($_GET);
17218        $logFileName = 'card_charge';
17219        $formType = Configure::read('payment_credit_force_charge');
17220        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType)); // get user data and validate
17221        $requestQuery = $this->request->query;
17222        $apiToken = $requestQuery['token'];
17223        $paymentPlanId = Configure::read('payment_plans.premium_plan');
17224        $cardToken = isset($requestQuery['cardToken']) ? $requestQuery['cardToken'] : '';
17225        $memKey = 'mobappUserCreditChargeInfo_'.$apiToken;
17226        $userDataArr = $userData['User'];
17227        $corporateChargeMemData = array();
17228        $requestData = $this->request->data;
17229
17230        // get premium payment plan data
17231        $paymentData = $this->PaymentPlanPrice->getPaymentData(array(
17232            'currencyCode' => $userDataArr['currency_code'],
17233            'paymentPlanId' => $paymentPlanId,
17234            'logFileName' => $logFileName
17235        ));
17236
17237        if (!$paymentData) {
17238            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
17239        }
17240
17241        $amount = $paymentData['amount'];
17242        $fAmount = $paymentData['fAmount'];
17243        $retainIndiPlan = null;
17244        $corporateIndiUser = false;
17245
17246            $corporateUser = isset($userDataArr['corporate_id']) ? true : false;
17247    
17248            $this->Corporate->openDBReplica();
17249            $corporateData = $this->Corporate->find('first', array(
17250                    'fields' => array('payment_method'),
17251                    'conditions' => array('id' => $userDataArr['corporate_id']),
17252                    'recursive' => -1
17253            ));
17254            $this->Corporate->closeDBReplica();
17255    
17256            $corporateData = $corporateData ? $corporateData['Corporate'] : null;
17257
17258        // if corporate user
17259        if ($corporateUser && $corporateData && $corporateData['payment_method'] == 1) {
17260            
17261            // NJ-28462 Organize the re-enrollment behavior after corporate plan end From bug ticket
17262            $cpData = $this->getCorporatePaymentPlan($userDataArr);
17263            if (!$cpData) {
17264                return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
17265            }
17266            $corporateIndiUser = $cpData;
17267
17268            // check if corporate user retain as individual plan using new card
17269            if (!$retainIndiPlan = isset($requestQuery['retainIndiPlan']) ? $requestQuery['retainIndiPlan'] : null) {
17270                // check if corporate user retain as individual plan using existing card
17271                $retainIndiPlan = isset($requestData['ZPaymentFullLogs']['retainIndiPlan']) ? $requestData['ZPaymentFullLogs']['retainIndiPlan'] : null;
17272            }
17273
17274            if ($retainIndiPlan) {
17275                // get corporate user individual payment plan data
17276                if ($corporateChargeMemData = $this->memcache->get('mobappCreditChargeCorporateData_' . $userDataArr['id'])) {
17277                    $formType = myTools::getCorporateCompanyCardFormType($corporateChargeMemData['paymentPlanId']);
17278                    $amount = (int)$corporateChargeMemData['paymentAmount'];
17279                    $fAmount = $corporateChargeMemData['fAmount'];
17280                }
17281            }
17282        }
17283        // - set receivable 
17284        $receivablePayment =  $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id']);
17285
17286        // get live lesson payment receivable
17287        $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('appreciation_data.payment_element_type'));
17288
17289        // get live lesson payment receivable
17290        $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('payment_element_type.live'));
17291
17292        $corporateTaxRate = Configure::read('tax.increase');
17293
17294        $mobappCorpIndividualData = array(
17295            'apiToken' => $apiToken,
17296        );
17297        if ($corporateIndiUser) {
17298            $this->corpIndividualData($userDataArr, $mobappCorpIndividualData);
17299        }
17300        $annualDiscountOptionData = $this->DiscountOptionsPrice->getPaymentData(['currencyCode' => $userDataArr['currency_code'], 'discountOptionId' => Configure::read('discount_option.annual.plan_id')]);
17301        $annualDiscountOptionAmount = 0;
17302
17303        // - check if there is annual discount option data
17304        if ($annualDiscountOptionData) {
17305            unset($annualDiscountOptionData['contract_start']);
17306            $annualDiscountOptionData += [
17307                'dosh_event' => Configure::read('discount_option.dosh_event.annual_discount'),
17308                'dosh_status' => Configure::read('discount_option.dosh_status.monthly_discount')
17309            ];
17310
17311            $annualDiscountOptionAmount = $annualDiscountOptionData['amount'];
17312        }
17313
17314        $monthlyPriceWithAnnualDiscount = $paymentData['amount'] - $annualDiscountOptionAmount;
17315        $monthlyPriceWithAnnualDiscountNoTax = $monthlyPriceWithAnnualDiscount / $corporateTaxRate;
17316        $monthlyPriceWithAnnualDiscountNoTax = round($monthlyPriceWithAnnualDiscountNoTax);
17317
17318        $this->set('enableAnnualDiscountOption', $annualDiscountOptionData ? true : false);
17319        $this->set('annualDiscountOptionAmount', myTools::formatAmount($annualDiscountOptionAmount));
17320        $this->set('monthlyPriceWithAnnualDiscount', myTools::formatAmount($monthlyPriceWithAnnualDiscount));
17321        $this->set('monthlyPriceWithAnnualDiscountNoTax', myTools::formatAmount($monthlyPriceWithAnnualDiscountNoTax));
17322
17323        // check if post
17324        if ($this->request->is('post')) {
17325            $data = $this->request->data;
17326
17327            // NJ-32737
17328            $couponData = $this->Session->read('apply_coupon_usage_data');
17329
17330            if (
17331                $annualDiscountOptionData &&
17332                isset($data['ZPaymentFullLogs']['payment_plan_type']) &&
17333                $data['ZPaymentFullLogs']['payment_plan_type'] == Configure::read('register_plan_types.premium_with_annual_discount_option')
17334            ) {
17335                $userDataArr['paymentAmount'] -=  $annualDiscountOptionData['amount'];
17336                $data['discountOption'] = $userDataArr['discountOption'] = $annualDiscountOptionData;
17337            }
17338
17339            $isLitePlanFlg = false;
17340            $isChocottoPlanFlg = false;
17341
17342            if (
17343                isset($data['ZPaymentFullLogs']['payment_plan_type']) && 
17344                !$corporateIndiUser
17345            ) {
17346
17347                $isLitePlan = $isLitePlanFlg = ((int) $data['ZPaymentFullLogs']['payment_plan_type']  == 1) ? true : false;
17348                $isChocottoPlan = $isChocottoPlanFlg = ((int) $data['ZPaymentFullLogs']['payment_plan_type']  == Configure::read('register_plan_types.chocotto'));
17349
17350                if ($isLitePlan) {
17351                    $_plan_id = Configure::read('payment_plans.light_plan');
17352                    $formType = myTools::getLitePlanUserFormType($_plan_id);
17353                } elseif ($isChocottoPlan) {
17354                    $_plan_id = Configure::read('payment_plans.chocotto_plan');
17355                    $formType = Configure::read('payment_credit_chocotto_force_charge');
17356                }else{
17357                    $_plan_id = Configure::read('payment_plans.premium_plan');
17358                    $formType = Configure::read('payment_credit_force_charge');
17359                }
17360
17361                // fetch light plan description
17362                $litePlanData = $this->PaymentPlanPrice->getPaymentData(array(
17363                    'currencyCode' => $userDataArr['currency_code'],
17364                    'paymentPlanId' => $_plan_id,
17365                    'logFileName' => 'card_reregister'
17366                ));
17367
17368                if (!$litePlanData) {
17369                    return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
17370                }
17371
17372                // update payment plan data 
17373                $paymentData = $litePlanData;
17374
17375                $userDataArr['paymentAmount'] = $paymentData['amount'];
17376                $userDataArr['price_id'] = $paymentData['priceId'];
17377                $userDataArr['payment_plan_id'] = $paymentData['paymentPlanId'];
17378
17379                // add reserve payment receivable
17380                $userDataArr['paymentAmount'] +=  $receivablePayment;
17381
17382                // add appreciation payment receivable
17383                $userDataArr['paymentAmount'] +=  $appreciationReceivable;
17384
17385                // add live lesson payment receivable
17386                $userDataArr['paymentAmount'] +=  $liveLessonReceivable;
17387
17388                // NJ-32737
17389                $membershipStatusIndex = UserTable::getStudentMembershipStatus($userDataArr['id']);
17390                if (in_array($membershipStatusIndex, Configure::read('allow_coupon.settlement')) &&
17391                    isset($formType) &&
17392                    in_array($formType, Configure::read('allow_coupon.settlement_form_type'))
17393                ) {
17394                    if (isset($couponData['useCouponAmount']) && $couponData['useCouponAmount'] > 0) {
17395                        if ($paymentData['amount'] >= $couponData['useCouponAmount']) {
17396                            $total_coupon_used = $couponData['useCouponAmount'];
17397                        } else {
17398                            $total_coupon_used = $paymentData['amount'];
17399                        }
17400
17401                        $userDataArr['couponUseSettlement'] = $couponData;
17402                    }
17403                }
17404                // NJ-32737-end
17405
17406                // - update form type
17407                $data['formType'] = $formType;
17408
17409                // redirect to retry page if failed to create payment transaction
17410                if (!$npt = $this->createPaymentTransaction($formType, $userDataArr)) {
17411                    return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
17412                }
17413
17414                // update payment hash , form type and money
17415                $data['ZPaymentFullLogs']['paymentHash'] = $npt['payment_hash'];
17416                $data['ZPaymentFullLogs']['money'] = $litePlanData['amount'] - $total_coupon_used;
17417                $data['ZPaymentFullLogs']['formType'] = $formType;
17418            }else{
17419                $npt = true;
17420            }
17421
17422            // redirect to paypal confirm page if payment gateway selected is paypal
17423            if ($data['payment_gateway_type'] == Configure::read('card_company.paypal')) {
17424                    $data['paymentPlanData'] = $paymentData;
17425                    $data['receivablePayment'] = $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id']);
17426                    $data['appreciationReceivable'] = $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('appreciation_data.payment_element_type'));
17427                    $data['liveLessonReceivable'] = $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('payment_element_type.live'));
17428                    $data['formType'] = $formType;
17429                    $this->memcache->set(array(
17430                        'key' => 'mobappPaypalPaymentCreditChargeData_' . $apiToken,
17431                        'value' => $data,
17432                        'expire' => 3600 // 1 hour
17433                    ));
17434                    return $this->redirect(myTools::getUrl() . '/mobapp/payment/paypal_payment_credit_charge_confirm?token=' . $apiToken);
17435            }
17436
17437            // delete payment gateway type memcache
17438            $this->memcache->delete('mobappCreditChargePaymentGatewayType_' . $apiToken);
17439
17440            $data['token'] = $apiToken;
17441            $data['ZPaymentFullLogs']['telno'] = Configure::read('credit.default_telno');
17442            $data['ZPaymentFullLogs']['clientip'] = Configure::read('ZEUS_clientip');
17443            $data['cardToken'] = $cardToken;
17444            $data['ZPaymentFullLogs']['indiCorpType'] = 1;
17445
17446            if($corporateIndiUser && isset($data['ZPaymentFullLogs']['corporatePlan']) && !$isLitePlanFlg && !$isChocottoPlanFlg) {
17447                    if($data['ZPaymentFullLogs']['corporatePlan'] == 'light') {
17448                        $getPaymentPlanId = $this->getCorporatePaymentPlan($userDataArr,array('corporate_type' => 4));
17449                        $getLightCorporateData = $this->Corporate->getCorporateLightUserMonthly(array(
17450                            'user_id' => $userDataArr['id'],
17451                            'remove_heavy_flg' => true
17452                        ));
17453                        $paymentLightAmount = isset($getLightCorporateData['total']) ? $getLightCorporateData['total'] : 0;
17454                        $basicLightFee = isset($getLightCorporateData['basic_fee']) ? $getLightCorporateData['basic_fee'] : 0;
17455                        $lessonLightFee = isset($getLightCorporateData['lesson_fee']) ? $getLightCorporateData['lesson_fee'] : 0;
17456                        $basicLightFeeWoTax = isset($getLightCorporateData['basic_fee_discounted']) ? $getLightCorporateData['basic_fee_discounted'] : 0;
17457                        $freeLightNumber = isset($getLightCorporateData['fee_charge_count']) ? $getLightCorporateData['fee_charge_count'] : 0;
17458                        $isLightFreeFlg = isset($getLightCorporateData['free_charge_flg']) ? $getLightCorporateData['free_charge_flg'] : false;
17459                        $monthlyLightFee = isset($getLightCorporateData['monthly_fee_wo_tax']) ? $getLightCorporateData['monthly_fee_wo_tax'] : 0;
17460                        $cfLightAmount = myTools::formatAmount($basicLightFeeWoTax);
17461                        $cLightRawAmount = $basicLightFeeWoTax;
17462                        $lessonLightLimit = $this->Corporate->getLessonLimit($userDataArr['corporate_id']);
17463                        $cpData = array(
17464                            'basicFee' => $basicLightFee,
17465                            'lessonFee' => $lessonLightFee,
17466                            'freeFlg' => $isLightFreeFlg,
17467                            'freeNumber' => $freeLightNumber,
17468                            'monthlyFee' => $monthlyLightFee,
17469                            'fAmount' => $cfLightAmount,
17470                            'paymentAmount' => $paymentLightAmount,
17471                            'lessonLimit' => $lessonLightLimit,
17472                            'paymentPlanId' => $getPaymentPlanId['paymentPlanId'],
17473                            'cRawAmount'    => $cLightRawAmount,
17474                            'basicFeeWoTax' => $basicLightFeeWoTax,
17475                            'priceId'        => $getPaymentPlanId['priceId']
17476                        );
17477        
17478                        $data['ZPaymentFullLogs']['indiCorpType'] = 4;
17479                    } else if($data['ZPaymentFullLogs']['corporatePlan'] == 'premium') {
17480                        $cpPremuimData = $this->getCorporatePaymentPlan($userDataArr,array('corporate_type' => 2));
17481                        
17482                        $cdrPremiumParam = array('corporateId' => $userDataArr['corporate_id'], 'corporateType' => 2);
17483                        $discountPremium = (int)$this->CorporateDiscountRate->getDiscount($cdrPremiumParam);
17484                        $cPremiumAmount = (int)$cpPremuimData['amount'] - $discountPremium;
17485                        $cPremiumRawAmount = $cPremiumAmount;
17486                        $cfPremiumAmount = myTools::formatAmount($cPremiumAmount);
17487                        $cpData = array(
17488                            'cprAmount' => $cpPremuimData['amount'],
17489                            'cprDiscount' => $discountPremium,
17490                            'paymentAmount' => $cPremiumAmount * $corporateTaxRate,
17491                            'fAmount' => $cfPremiumAmount,
17492                            'cRawAmount' => $cPremiumRawAmount,
17493                            'ppAmount' => $cpPremuimData,
17494                            'paymentPlanId' => $cpPremuimData['paymentPlanId'],
17495                            'priceId'        => $cpPremuimData['priceId']
17496                        );
17497        
17498                        $data['ZPaymentFullLogs']['indiCorpType'] = 2;
17499                    } else {
17500                        $cpStandardData = $this->getCorporatePaymentPlan($userDataArr,array('corporate_type' => 1));
17501                        $cdrStandardParam = array('corporateId' => $userDataArr['corporate_id'], 'corporateType' => 1);
17502                        $discountStandard = (int)$this->CorporateDiscountRate->getDiscount($cdrStandardParam);
17503                        $cStandardAmount = (int)$cpStandardData['amount'] - $discountStandard;
17504                        $cStandardRawAmount = $cStandardAmount;
17505                        $cfStandardAmount = myTools::formatAmount($cStandardAmount);
17506                        $cpData = array(
17507                            'cprAmount' => $cpStandardData['amount'],
17508                            'cprDiscount' => $discountStandard,
17509                            'paymentAmount' => $cStandardAmount * $corporateTaxRate,
17510                            'fAmount' => $cfStandardAmount,
17511                            'cRawAmount' => $cStandardRawAmount,
17512                            'ppAmount' => $cpStandardData,
17513                            'paymentPlanId' => $cpStandardData['paymentPlanId'],
17514                            'priceId'        => $cpStandardData['priceId']
17515                        );
17516                        $data['ZPaymentFullLogs']['indiCorpType'] = 1;
17517                    }
17518                    $data['ZPaymentFullLogs']['formType'] = $formType = myTools::getCorporateCompanyCardFormType($cpData['paymentPlanId']);
17519                    $corpIndiPrices = $this->memcache->get('mobappcorporateIndiPrices_'.$userDataArr['api_token']);
17520                    $corpIndiPrices[$data['ZPaymentFullLogs']['corporatePlan']]['plan_type'] = $data['ZPaymentFullLogs']['indiCorpType'];
17521                    $amount = (int)$corpIndiPrices[$data['ZPaymentFullLogs']['corporatePlan']]['paymentAmount'];
17522                    $fAmount = $corpIndiPrices[$data['ZPaymentFullLogs']['corporatePlan']]['fAmount'];
17523    
17524                    $this->memcache->set(array(
17525                        'key' => 'mobappCreditChargeCorporateData_' . $userDataArr['id'],
17526                        'value' => $corpIndiPrices[$data['ZPaymentFullLogs']['corporatePlan']],
17527                        'expire' => 3600 // 1 hour
17528                    ));
17529    
17530                    $corporateChargeMemData = $this->memcache->get('mobappCreditChargeCorporateData_' . $userDataArr['id']);
17531    
17532                    // corporate light
17533                    if (
17534                        $corporateChargeMemData['plan_type'] == Configure::read('corporate_type.light') &&
17535                        isset($corporateChargeMemData['lessonFee']) &&
17536                        isset($corporateChargeMemData['basicFee'])
17537                    ) {
17538                        $userDataArr['lesson_fee'] = (int)$corporateChargeMemData['lessonFee'];
17539                        $userDataArr['basic_fee'] = (int)$corporateChargeMemData['basicFee'];
17540                    // standard or premium
17541                    } else {
17542                        if (isset($corporateChargeMemData['cprAmount']) && isset($corporateChargeMemData['cprDiscount'])) {
17543                            $userDataArr['cprAmount'] = (int)$corporateChargeMemData['cprAmount'];
17544                            $userDataArr['cprDiscount'] = (int)$corporateChargeMemData['cprDiscount'];
17545                        }
17546                    }
17547    
17548                    $userDataArr['corporateSettlementType'] = Configure::read('corporate_settlement_types.force_charge_payment');
17549                    $userDataArr['paymentAmount'] = $amount;
17550                    $userDataArr['price_id'] = $cpData['priceId'];
17551                    $userDataArr['payment_plan_id'] = $cpData['paymentPlanId'];
17552                    $userDataArr['corporate_type'] = $data['ZPaymentFullLogs']['indiCorpType'];
17553                    $formType = myTools::getCorporateCompanyCardFormType($cpData['paymentPlanId']);
17554    
17555                    $membershipTypes = UserTable::getEngMembershipTypeData();
17556                    $userDataArr['statusAfter'] =  myTools::getCorporateUserMembershipStatusName($membershipTypes, $userDataArr['payment_plan_id']);
17557    
17558                    $userTable = new UserTable($userDataArr);
17559                    // add statusBefore and statusAfter if free "Trial not yet conducted"
17560                    if ($userTable->getMembershipTypeIndex() == 13) {
17561                        $userDataArr['statusBefore'] = $membershipTypes[13];
17562                        $userDataArr['statusAfter'] = myTools::getCorporateUserMembershipStatusName($membershipTypes, $userDataArr['payment_plan_id']);
17563                    }
17564
17565                    //- check chocotto camp membership
17566                    if (in_array(
17567                        $userDataArr['payment_plan_id'],
17568                        [
17569                            Configure::read('payment_plans.free_trial_chocotto'),
17570                            Configure::read('payment_plans.chocotto_plan')
17571                        ]
17572                    )) {
17573                        $userDataArr['statusAfter'] = $membershipTypes[Configure::read('membership_type_chocotto_plan_paid')];
17574                    }
17575    
17576                    if ($retainIndiPlan) {
17577                        $data['ZPaymentFullLogs']['retainIndiPlan'] = $retainIndiPlan;
17578                    }
17579    
17580                    if ($corporateIndiUser && $corporateChargeMemData) {
17581                        // save new card charge token to memcache
17582                        $this->memcache->set(array(
17583                            'key' => 'card-charge-'.$apiToken,
17584                            'value' => $cardToken,
17585                            'expire' => 3600
17586                        ));
17587                    }
17588    
17589            } // End of Check Corporate Individual
17590
17591            // NJ-25522: Skip confirm page if using 3D secure challenge
17592            $zeus3DSecureChallengeFlg = $this->memcache->get('zeus3DSecureChallengeFlg_' . $userDataArr['id']);
17593            
17594            if ($zeus3DSecureChallengeFlg) {
17595                    // unset previously set tokens
17596                    $this->unsetTokenMobapp($apiToken, 'card-charge-');
17597
17598                    $formType = isset($data['ZPaymentFullLogs']['formType']) ? $data['ZPaymentFullLogs']['formType'] : $formType;
17599
17600                    // if corporate credit charge
17601                    if (
17602                        $formType != Configure::read('payment_credit_force_charge') && 
17603                        !$isLitePlanFlg &&
17604                        !$isChocottoPlanFlg
17605                    ) {
17606                        $data['ZPaymentFullLogs']['money'] = $fAmount;
17607                    }
17608
17609                    if($corporateIndiUser) {
17610                        $data['ZPaymentFullLogs']['paymentHash'] = $this->memcache->get('indiCorpPaymentHash_'.$userDataArr['id']);
17611                    }
17612                     
17613                    $totalReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id']) + $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('appreciation_data.payment_element_type')) + $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('payment_element_type.live'));
17614
17615                    $data['ZPaymentFullLogs']['money'] += $totalReceivable;
17616                    $data['ZPaymentFullLogs']['money'] -= $annualDiscountOptionAmount;
17617
17618                    $this->Session->write('mobapp_show_welcome_back_modal',true);
17619                    //process zeus card
17620                    $this->zeus_card_process_mobapp(array(
17621                        'data' => $data,
17622                        'form_type' => $formType,
17623                        'referrer' => array('controller' => 'Payment', 'action' => 'mobapp_credit_charge', '?' => array('token' => $apiToken)),
17624                        'api_token' => $apiToken
17625                    ));
17626
17627            }
17628
17629            if(!$zeus3DSecureChallengeFlg && $corporateIndiUser) {
17630                $data['userApiToken'] = $apiToken;
17631                $data['userData'] = $userDataArr;
17632                $corpIndiPT = $this->createCorporateIndividualPayment($data);
17633                $data['ZPaymentFullLogs']['paymentHash'] = $corpIndiPT['paymentHash'];
17634                $data['ZPaymentFullLogs']['money'] = $corpIndiPT['paymentAmount'];
17635            }
17636
17637            // delete memcache if exist
17638            if ($this->memcache->get($memKey)) {
17639                $this->memcache->delete($memKey);
17640            }
17641
17642            // set memcache
17643            $this->memcache->set(array(
17644                'key' => $memKey,
17645                'value' => $data,
17646                'expire' => 3600
17647            ));
17648
17649            return $this->redirect(myTools::getUrl() . '/payment/mobapp_credit_charge_confirm'.$urlParams);
17650        
17651        } else {
17652            // delete payment gateway type memcache
17653            $this->memcache->delete('mobappCreditChargePaymentGatewayType_' . $apiToken);
17654
17655            $this->set('data', $this->memcache->get($memKey));
17656        }
17657
17658        // if not retain indi plan
17659        if (!$corporateIndiUser) {
17660            $userDataArr['paymentAmount'] = $paymentData['amount'];
17661            $userDataArr['price_id'] = $paymentData['priceId'];
17662            $userDataArr['payment_plan_id'] = $paymentData['paymentPlanId'];
17663
17664            $data['ZPaymentFullLogs']['formType'] = $formType;
17665
17666            // add reserve payment receivable
17667            $userDataArr['paymentAmount'] +=  $receivablePayment;
17668
17669            // add appreciation payment receivable
17670            $userDataArr['paymentAmount'] +=  $appreciationReceivable;
17671
17672            // add live lesson payment receivable
17673            $userDataArr['paymentAmount'] +=  $liveLessonReceivable;
17674
17675            // redirect to retry page if failed to create payment transaction
17676            if (!$pt = $this->createPaymentTransaction($formType, $userDataArr)) {
17677                return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
17678            }
17679
17680            $data['ZPaymentFullLogs']['paymentHash'] = $pt['payment_hash'];
17681
17682        }
17683
17684        // delete memcache if exist
17685        if ($this->memcache->get($memKey)) {
17686            $this->memcache->delete($memKey);
17687        }
17688
17689        // set memcache
17690        $this->memcache->set(array(
17691            'key' => $memKey,
17692            'value' => $data,
17693            'expire' => 3600
17694        ));
17695
17696        // NJ-32737
17697        $this->setCouponUseData($userDataArr['id'], $userDataArr['currency_code']);
17698
17699        // set the view vars
17700        $this->set('cardToken', $cardToken);
17701        $this->set('apiToken', $apiToken);
17702        $this->set('zeusTransactionFlag', true);
17703        $this->set('corporateIndiUser',$corporateIndiUser);
17704        $this->set('monthlyPrice', $amount);
17705        $this->set('monthylyPriceNoTax', myTools::formatAmount($paymentData['amountConstTaxDeducted']));
17706        $this->set('monthlyPriceSymbol',myTools::getCurrencySymbol($userDataArr['currency_code']));
17707        $this->set('amount', $amount);
17708        $this->set('fAmount', $fAmount);
17709        $this->set('paymentHash', isset($pt['payment_hash']) ? $pt['payment_hash'] : "");
17710        $this->set('retainIndiPlan', $retainIndiPlan);
17711        $this->set('failURLReferer', myTools::getUrl() . "/mobapp/payment/credit_charge?token=" . $apiToken);
17712        $this->render(myTools::getDeviceUrl() . 'Payment/credit_charge_form');
17713    }
17714
17715    /**
17716     * @api {post} /mobapp/payment_wp_credit_charge/:token mobapp_wp_credit_charge()
17717     * @apiName mobapp_wp_credit_charge
17718     * @apiGroup Payment
17719     * @apiDescription This endpoint is used to charge the user's credit card.
17720     * 
17721     * @apiParam {String} token User's token
17722     * 
17723     * @apiBody {Number} cardType 0 for existing card, 1 for new card
17724     * 
17725     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/wp_credit_charge_form?token={{token}} if cardType is 1
17726     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/wp_credit_charge_confirm?token={{token}} if cardType is 0
17727     * 
17728     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if there is an error
17729     * 
17730     * @apiSuccessExample Success Response Existing card:
17731     * Redirects to {{ENV}}/mobapp/payment/wp_credit_charge_confirm?token={{token}}
17732     * 
17733     * @apiSuccessExample Success Response New card:
17734     * Redirects to {{ENV}}/mobapp/payment/wp_credit_charge_form?token={{token}}
17735     * 
17736     * @apiErrorExample Error Response:
17737     * Redirects to {{ENV}}/mobapp/retrypage
17738     * 
17739     * @apiSampleRequest off
17740     */
17741    public function mobapp_wp_credit_charge() {
17742
17743        if ($this->Session->read('credit_skip_to_confirmation')) {
17744            $this->Session->delete('credit_skip_to_confirmation');
17745        }
17746
17747
17748        $this->blockWithdrawnSapuriToS('mobapp');
17749        $this->disablePageForSapuri('mobapp');
17750        
17751        // set variables
17752        $logFileName = 'card_charge';
17753        $formType = Configure::read('payment_credit_force_charge');
17754        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType));
17755        $userData = $userData['User'];
17756        $this->layout = "mobapp";
17757        $this->response->disableCache();
17758        $apiToken = $userData['api_token'];
17759        $currencyCode = $userData['currency_code'];
17760        $memKey = "credit_charge_{$userData['id']}_{$currencyCode}";
17761        $cardType = $this->memcache->get($memKey);
17762        $cardType = isset($cardType) ? $cardType : 0;
17763
17764        $this->restrictForTrialNotConducted($userData, myTools::getMobappToken($_GET));
17765        // get monthly price
17766        $amount = $this->PaymentPlanPrice->getMonthlyPrice(array(
17767            'currencyCode' => $currencyCode,
17768            'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
17769            'logFileName' => $logFileName
17770        ));
17771
17772        if (!isset($amount)) {
17773            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.myTools::getMobappToken($_GET));
17774        }
17775
17776        $isFamilyPlanBefore = PaymentTable::checkIfFamilyPlan(
17777            $userData['id'],
17778            $userData['hash16'],
17779            array(
17780                Configure::read('payment_credit_family_free'),
17781                Configure::read('payment_credit_family_monthly_payment')
17782            )
17783        );
17784
17785        // if complimentary plan
17786        if ($comPlanUser = isset($userData['com_plan_user']) && $userData['com_plan_user'] ? $userData['com_plan_user'] : false) {
17787            $this->set('cPlan', $comPlanUser);
17788        }
17789
17790        // redirect to form page if child and parent unsubscribed
17791        if ( 
17792            (empty($userData['card_company']) && empty($userData['card_brand']) && empty($userData['card_token']) && empty($userData['card_number'])) ||
17793            ($userData['card_brand'] == 'AFTEE2' && empty($userData['card_company']))
17794        ) {
17795            $this->memcacheCardType(array(
17796                'key' => $memKey,
17797                'value' => array('cardType' => $cardType)
17798            ));
17799            $this->redirect(myTools::getUrl() . "/mobapp/payment/wp_credit_charge_form".myTools::getMobappToken($_GET)."&com_plan_user={$comPlanUser}");
17800        }
17801
17802        if ($this->request->is('post')) {
17803            $cardType = $this->request->data['cardType'];
17804
17805            // memcache card type value
17806            $this->memcacheCardType(array(
17807                'key' => $memKey,
17808                'value' => $cardType
17809            ));
17810
17811            // redirect to hosted page if using new card ($cardType = 1)
17812            if ($cardType) {
17813                 $this->redirect(myTools::getUrl() . "/mobapp/payment/wp_credit_charge_form".myTools::getMobappToken($_GET)."&com_plan_user={$comPlanUser}");
17814            // redirect to confirm page if using existing card ($cardType = 0)
17815            } else {
17816
17817                // - NJ-23812: write session to skip and auto charge 
17818                $this->Session->write('credit_skip_to_confirmation',true);
17819
17820                $this->redirect(myTools::getUrl() . "/mobapp/payment/wp_credit_charge_confirm?token=$apiToken");
17821            }
17822        }
17823
17824        // // check if there is error
17825        // if ($error = $this->memcache->get('card_charge_error_'. $apiToken)) {
17826        //     $this->memcache->delete('card_charge_error_'. $apiToken);
17827        //     $this->set('error', $error);
17828        // }
17829
17830        // set view variables
17831        $this->set('cardLogo', myTools::getWorldpayCardLogo($userData['card_brand']));
17832        if(
17833            (is_null($userData['card_number']) || is_null($userData['card_brand'])) &&
17834            ($isFamilyPlanBefore)
17835        ){
17836            $cardType = 1; // set as default
17837        }
17838        $this->set('cardType', $cardType);
17839        $this->set('apiToken', $apiToken);
17840        $this->set('user', $userData);
17841        $this->set('title_for_layout', '再入会');
17842        $this->render(myTools::getDeviceUrl() . 'Payment/wp_credit_charge');
17843
17844        // NJ-32737
17845        $this->setCouponUseData($userData['id'], $userData['currency_code']);
17846
17847        // NJ-23812 redirect to change form
17848        return  $this->redirect(myTools::getUrl() . "/mobapp/payment/wp_credit_charge_form?token={$apiToken}&com_plan_user={$comPlanUser}");
17849    }
17850
17851    /**
17852     * @api {get} /mobapp/payment/wp_credit_charge_form/:token mobapp_wp_credit_charge_form()
17853     * @apiName mobapp_wp_credit_charge_form
17854     * @apiGroup Payment
17855     * @apiDescription This endpoint is used to process the form for charging the user's credit card.
17856     * 
17857     * @apiParam {String} token User's token
17858     * @apiParam {Boolean} [com_plan_user] Indicates if user is a complimentary plan user
17859     * 
17860     * @apiSuccess {View} Redirect Redirects to {{ENV}}/user/mobapp/close?token={{token}}&type=special_complimentary_plan if user is a complimentary plan user
17861     * @apiSuccess {View} Redirect Redirects to {{ENV}}/user/mobapp/close?token={{token}}&type=premium_plan_paid if user is not a complimentary plan user
17862     * 
17863     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if there is an error
17864     * 
17865     * @apiSuccessExample Success Response Complimentary Plan User:
17866     * Redirects to {{ENV}}/user/mobapp/close?token={{token}}&type=special_complimentary_plan
17867     * 
17868     * @apiSuccessExample Success Response Premium Plan User:
17869     * Redirects to {{ENV}}/user/mobapp/close?token={{token}}&type=premium_plan_paid
17870     * 
17871     * @apiErrorExample Error Response:
17872     * Redirects to {{ENV}}/mobapp/retrypage
17873     * 
17874     * @apiSampleRequest off
17875     */
17876    public function mobapp_wp_credit_charge_form() {
17877
17878        if ($this->Session->read('credit_skip_to_confirmation')) {
17879            $this->Session->delete('credit_skip_to_confirmation');
17880        }
17881
17882        $this->blockWithdrawnSapuriToS('mobapp');
17883        $this->disablePageForSapuri('mobapp');
17884        // set variables
17885        $logFileName = 'card_charge';
17886        $formType = Configure::read('payment_credit_force_charge');
17887        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType));
17888        $apiToken = $userData['User']['api_token'];
17889        $user = $userData['User'];
17890        $this->layout = "mobapp";
17891        $this->response->disableCache();
17892
17893        // - NJ-23812: support 
17894        $memKey = "credit_charge_{$userData['id']}_{$currencyCode}";
17895        $cardType = $this->memcache->get($memKey);
17896        $cardType = isset($cardType) ? $cardType : 0;
17897        // - NJ-23812- support end
17898
17899        // check if allowed aftee
17900        $this->checkAfteeSupported($userData['User']);
17901
17902        $this->setPerMonthSymbol($user['native_language2'], true);
17903
17904        // set view variables
17905        $this->set('pmtValue', 'payment');
17906        $this->set('apiToken', $apiToken);
17907        $this->set('logFileName', $logFileName);
17908        $this->set('worldpayFlg', true);
17909        $this->set('memKeyError', 'card_charge_error_'.$apiToken);
17910        $this->set('referrer', urlencode(myTools::getUrl()."/mobapp/payment/wp_credit_charge_form?token={$apiToken}"));
17911
17912        if ($this->Session->read('mobapp_show_welcome_back_modal')) {
17913            $this->Session->delete('mobapp_show_welcome_back_modal');
17914        }
17915
17916
17917        // - NJ-23812 : support start 
17918
17919        // check if there is error
17920        if ($error = $this->memcache->get('card_charge_error_'. $apiToken)) {
17921            $this->memcache->delete('card_charge_error_'. $apiToken);
17922            $this->set('error', $error);
17923        }
17924    
17925        
17926
17927        $isCardRegistered = (!empty($user['card_brand']) && !empty($user['card_number'])) ? true : false;
17928        $comPlanUser = (isset($user['com_plan_user']) && $user['com_plan_user']) ? $user['com_plan_user'] : false;
17929
17930        $isFamilyPlanBefore = PaymentTable::checkIfFamilyPlan(
17931            $user['id'],
17932            $user['hash16'],
17933            array(
17934                Configure::read('payment_credit_family_free'),
17935                Configure::read('payment_credit_family_monthly_payment')
17936            )
17937        );
17938        if(
17939            (is_null($user['card_number']) || is_null($user['card_brand'])) &&
17940            ($isFamilyPlanBefore)
17941        ){
17942            $cardType = 1; // set as default
17943        }
17944
17945        // - set for the payment plan detais 
17946        $this->setPaymentPlanDetails($user,Configure::read('payment_plans.premium_plan'),$logFileName);
17947
17948        // set view variables
17949        $this->set('isCardRegistered',$isCardRegistered);
17950        $this->set('cPlan', $comPlanUser);
17951        $this->set('user', $user);
17952        $this->set('cardLogo', myTools::getWorldpayCardLogo($user['card_brand']));
17953        $this->set('cardType', $cardType);
17954        $this->set('apiToken', $apiToken);
17955        $this->set('cardNumber', $user['card_number']);
17956        $this->set('cardBrand', $user['card_brand']);
17957        // - NJ-23812 : support end
17958
17959        // NJ-32737
17960        $this->setCouponUseData($user['id'], $user['currency_code']);
17961
17962        // if complimentary plan user
17963        if (isset($this->request->query['com_plan_user']) && $this->request->query['com_plan_user']) {
17964            $addWelcomeModal = "&re_enrolled=1";
17965            $this->set('successUrl', urlencode(myTools::getUrl()."/user/mobapp/close?token={$apiToken}&type=special_complimentary_plan{$addWelcomeModal}"));
17966        } else {
17967            $addWelcomeModal = "&re_enrolled=1";
17968            $this->set('successUrl', urlencode(myTools::getUrl()."/user/mobapp/close?token={$apiToken}&type=premium_plan_paid{$addWelcomeModal}"));
17969        }
17970
17971        $this->set('title_for_layout', '再入会');
17972        $this->set('formType', $formType);
17973        $this->render(myTools::getDeviceUrl() . 'Payment/wp_credit_charge_form');
17974    }
17975    /**
17976     * @api {post} /mobapp/payment/wp_credit_charge_confirm/:token mobapp_wp_credit_charge_confirm()
17977     * @apiName mobapp_wp_credit_charge_confirm
17978     * @apiGroup Payment
17979     * @apiDescription This endpoint is used to confirm the charging of the user's credit card.
17980     * 
17981     * @apiParam {String} token User's token
17982     * 
17983     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/close?token=$apiToken&type=special_complimentary_plan".$addWelcomeModal if user is a complimentary plan user
17984     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/close?token=$apiToken&type=premium_plan_paid".$addWelcomeModal if user is not a complimentary plan user
17985     * 
17986     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if there is an error
17987     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/payment/wp_credit_charge?token= if direct payment response is not authorized
17988     * 
17989     * @apiSuccessExample Success Response Complimentary Plan User:
17990     * Redirects to {{ENV}}/mobapp/close?token=$apiToken&type=special_complimentary_plan".$addWelcomeModal
17991     * 
17992     * @apiSuccessExample Success Response Premium Plan User:
17993     * Redirects to {{ENV}}/mobapp/close?token=$apiToken&type=premium_plan_paid".$addWelcomeModal
17994     * 
17995     * @apiErrorExample Error Response If there is an arror:
17996     * Redirects to {{ENV}}/mobapp/retrypage
17997     * 
17998     * @apiErrorExample Error Response Direct Payment Response Not Authorized:
17999     * Redirects to {{ENV}}/mobapp/payment/wp_credit_charge?token= with error message
18000     * 
18001     * @apiSampleRequest off
18002     */
18003    public function mobapp_wp_credit_charge_confirm() {
18004
18005        // NJ-23812
18006        $readSkipConfirmation = $this->Session->read('credit_skip_to_confirmation');
18007        if ($readSkipConfirmation) {
18008            $this->Session->delete('credit_skip_to_confirmation');
18009        }
18010
18011        // set variables
18012        $logFileName = 'card_charge';
18013        $formType = Configure::read('payment_credit_force_charge');
18014        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType));
18015        $this->layout = "mobapp";
18016        $this->response->disableCache();
18017        $userData = $userData['User'];
18018        $currencyCode = $userData['currency_code'];
18019        $userId = $userData['id'];
18020        $apiToken = $userData['api_token'];
18021        $memKey = "credit_charge_{$userId}_{$currencyCode}";
18022        $urlParams = myTools::getMobappToken($_GET);
18023
18024        // get payment data
18025        $pData = $this->PaymentPlanPrice->getPaymentData(array(
18026            'currencyCode' => $currencyCode,
18027            'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
18028            'logFileName' => $logFileName
18029        ));
18030
18031        // redirect to retry page if premium plan payment not supported
18032        if (!$pData) {
18033            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
18034        }
18035
18036        $userData['com_plan_user'] = ($userData['payment_plan_id'] == Configure::read('payment_plans.complimentary_plan')) ? true : false;
18037        $userData['payment_plan_id'] = $pData['paymentPlanId'];
18038        $userData['price_id'] = $pData['priceId'];
18039
18040        $currency_before = $userData['currency_code'];
18041        $plan_before = $userData['payment_plan_id'];
18042
18043        $readSkipConfirmation = true;//auto charge and skip confirmation
18044
18045        if ($this->request->is('post') || $readSkipConfirmation) {
18046
18047            // get reserve payment receivable
18048            $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userId);
18049
18050            // get appreciation payment receivable
18051            $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('appreciation_data.payment_element_type'));
18052
18053            // get live lesson payment receivable
18054            $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.live'));
18055
18056            // add force charge payment, receivable payment amount and live lesson payment amount
18057            $totalAmount = $pData['amount'] + $receivablePayment + $appreciationReceivable + $liveLessonReceivable;
18058
18059            $paymentMethodType = myTools::getWPPaymentMethodType($userData['card_brand'], 'payment');
18060            $merchantCode = myTools::getWPMerchantCode($paymentMethodType);
18061            $paymentMethod = explode('_', $paymentMethodType);
18062            $paymentMethod = isset($paymentMethod[0]) ? $paymentMethod[0] : null;
18063            $orderCode = myTools::generateOrderCode($userId);
18064            $currencyExponents = Configure::read('worldpay.currency_exponents');
18065            $exponent = $currencyExponents[$currencyCode];
18066
18067            // NJ-32737
18068            $couponData = $this->Session->read('apply_coupon_usage_data');
18069            $membershipStatusIndex = UserTable::getStudentMembershipStatus($userData['id']);
18070            if (in_array($membershipStatusIndex, Configure::read('allow_coupon.settlement')) &&
18071                isset($formType) &&
18072                in_array($formType, Configure::read('allow_coupon.settlement_form_type'))
18073            ) {
18074                if (isset($couponData['useCouponAmount']) && $couponData['useCouponAmount'] > 0) {
18075                    if ($totalAmount >= $couponData['useCouponAmount']) {
18076                        $totalAmount -= $couponData['useCouponAmount'];
18077
18078                    } else {
18079                        $totalAmount = 0;
18080
18081                    }
18082
18083                    $userData['couponUseSettlement'] = $couponData;
18084                }
18085            }
18086            // NJ-32737-end
18087
18088            // get total amount with checking currency exponent
18089            $totalAmountArr = myTools::wpGetAmount($exponent, $totalAmount);
18090            $ncAmount = $totalAmountArr['ncAmount'];
18091            $wpAmount = $totalAmountArr['wpAmount'];
18092
18093            $wpData = array(
18094                'cardToken' => $userData['card_token'],
18095                'merchantCode' => $merchantCode,
18096                'paymentHash' => $orderCode,
18097                'wpPaymentAmount' => $wpAmount
18098            );
18099
18100            // set payment amount
18101            $userData['paymentAmount'] = $ncAmount;
18102
18103            // create payment transaction
18104            if (!$pt = $this->createPaymentTransaction($formType, $userData, $wpData)) {
18105                $this->log(__METHOD__ .' Failed to save payment transaction. Params --> ' . json_encode($wpData), $logFileName);
18106                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to save payment transaction. Params --> ' . json_encode($wpData), 'error');
18107                return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
18108            }
18109
18110            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - After save payment transaction. Params --> ' . json_encode($wpData), 'error');
18111            
18112            // if aftee payment
18113            if ($userData['card_company'] == Configure::read('card_company.aftee') || ($userData['card_brand'] == "AFTEE" && !empty($userData['aftee_transaction_identifier']))) {
18114
18115                if (!class_exists('AfteePaymentService')) {
18116                    App::uses('AfteePaymentService','Lib');
18117                }
18118                $afteeService = new AfteePaymentService();
18119                $afteeChecksumData = array(
18120                    'shopItemId' => "AFTEE" . $formType,
18121                    'itemName' => 'CreditForceChargeUsingExistingCard',
18122                    'itemPrice' => $totalAmount,
18123                    'itemCount' => 1,
18124                    'customerPhoneNumber' => $userData['phone_number'],
18125                    'customerEmail' => $userData['email'],
18126                    'shopTransactionNo' => $orderCode,
18127                    'userID' =>  $userData['id']
18128                );
18129                $checksum = $afteeService->generateChecksum($afteeChecksumData, false);
18130                $afteeData = array(
18131                    'authentication_token' => $userData['card_token'],
18132                    'related_id' => $userData['aftee_transaction_identifier'],
18133                    'checksum' => $checksum['checksum'],
18134                    'shop_transaction_no' => $orderCode,
18135                    'transaction_options' => array(1)
18136                );
18137        
18138                $afteePaymentData = array_merge($afteeData, $checksum['settlementData']);
18139    
18140                // aftee execute payment
18141                $receivableResult = $afteeService->directPayment($afteePaymentData);
18142                $checkRes = json_decode($receivableResult, true);
18143
18144
18145                if ( isset($checkRes['object']) && $checkRes['object'] == 'transaction') {
18146                    $prPaymentSuccess = true;
18147                } else if ( !array_key_exists("object", $checkRes) || (isset($checkRes['object']) && $checkRes['object'] == 'error')) {
18148                    $prPaymentSuccess = false;
18149                }
18150
18151                // set user model
18152                $uModel = $this->User;
18153                $dataSource = $uModel->getDataSource();
18154                $dataSource->begin();
18155
18156                $afteeTransactionIdentifier = isset($checkRes['id']) && !empty($checkRes['id']) ? $checkRes['id'] : NULL;
18157                if (isset($checkRes['related_transaction']) && !empty($checkRes['related_transaction'])) {
18158                    $afteeTransactionIdentifier = $checkRes['related_transaction'];
18159                }
18160                $orderCode = isset($checkRes['shop_transaction_no']) && !empty($checkRes['shop_transaction_no']) ? $checkRes['shop_transaction_no'] : NULL;
18161                $checkRes['OrderCode'] = $orderCode;
18162
18163                // payment transaction additional data
18164                $checkRes['OrderCode'] = $orderCode;
18165                $checkRes['authentication_token'] = $userData['card_token'];
18166                $checkRes['customer']['phone_number'] = $userData['phone_number'];
18167
18168                // process payment data
18169                if ($prPaymentSuccess) {
18170                    $afteeParams = array(
18171                        'data' => $checkRes,
18172                        'ptData' => $pt,
18173                        'logFileName' => $logFileName,
18174                        'dataSource' => $dataSource,
18175                        'amount' => $pData['amount'],
18176                        'userData' => $userData,
18177                        'receivablePayment' => $receivablePayment,
18178                        'appreciationReceivable' => $appreciationReceivable,
18179                        'liveLessonReceivable' => $liveLessonReceivable,
18180                        'transactionIdentifier' => $afteeTransactionIdentifier,
18181                        'aftee' => 1
18182                    );
18183    
18184                    $this->processAfteePayment($afteeParams);
18185                }
18186
18187                // update payment transaction
18188                $updateData = array(
18189                    'id' => $pt['id'],
18190                    'fields' => array(
18191                        'status' => $prPaymentSuccess,
18192                        'response_text' => array('aftee_directPayment_response' => $receivableResult))
18193                );
18194
18195                // update payment transaction
18196                $this->PaymentTransaction->updateAfteePaymentTransaction($updateData);
18197
18198
18199                // redirect to payment_credit_charge with error display if direct payment response is not authorised
18200                if (!$prPaymentSuccess) {
18201                    if (!class_exists('myMemcached')) {
18202                        App::uses('myMemcached', 'Lib');
18203                    }
18204                    $memKeyError = 'card_charge_error_' . $apiToken;
18205                    $memerror = __('トランザクションを完了できません。 もう一度お試しください。');
18206                    $memcached = new myMemcached();
18207                    $memcached->set(array(
18208                        'key' => $memKeyError,
18209                        'value' => $memerror,
18210                        'expire' => 3600 // 1 hour
18211                    ));
18212                    return $this->redirect(myTools::getUrl() . '/mobapp/payment/wp_credit_charge?token='.$apiToken);
18213                }
18214
18215
18216            // default worldpay payment
18217            } else {
18218
18219                $wpData = array(
18220                    'merchantCode' => $merchantCode,
18221                    'orderCode' => $orderCode,
18222                    'description' => 'Credit Force Charge Using Existing Card',
18223                    'currencyCode' => $currencyCode,
18224                    'exponent' => $exponent,
18225                    'amount' => $wpAmount,
18226                    'cardToken' => $userData['card_token'],
18227                    'email' => $userData['email'],
18228                    'authenticatedShopperId' => $userId,
18229                    'xmlName' => 'direct_payment_with_token',
18230                    'shopperIpAddress' => $_SERVER["REMOTE_ADDR"],
18231                    'wpTransactionIdentifier' => $userData['wp_transaction_identifier'],
18232                    'paymentMethod' => $paymentMethod
18233                );
18234                
18235                $result = wpPaymentService::directPayment($wpData);
18236
18237                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - directPayment result --> ' . json_encode($result), 'error');
18238
18239                $updateData = array(
18240                    'id' => $pt['id'],
18241                    'fields' => array('response_text' => array('directPayment_response' => $result)),
18242                    'logFileName' => $logFileName
18243                );
18244
18245                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - before updatePaymentTransaction result --> ' . json_encode($updateData), 'error');
18246
18247                // update payment transaction direct response.
18248                $this->updatePaymentTransaction($updateData);
18249
18250                // redirect to wp_credit_charge with error display if direct payment response is not a
18251                if (!myTools::checkIfWPPaymentResponseIsAuthorised($result)) {
18252                    $params = array(
18253                        'apiToken' => $apiToken,
18254                        'wpResponse' => $result,
18255                        'memKey' => 'card_charge_error_' . $apiToken
18256                    );
18257                    myTools::parseAndSetWPErrorResponse($params);
18258                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - WP Payment not authorised --> ' . json_encode($params), 'error');
18259                    return $this->redirect(myTools::getUrl() . '/mobapp/payment/wp_credit_charge?token='.$apiToken);
18260                }
18261            }
18262
18263            //    NC-7644 Add code reward for re-enroolling with the campaign code
18264            $this->addCoinRewardForReenroll($userData);
18265            
18266            // Teacher Perks : Student re-enroll
18267            ClassRegistry::init('TeacherPerksAccount')->reEnroll(['user_id' => $userData['id']]);
18268
18269            // delete memcache
18270            if ($this->memcache->get($memKey)) {
18271                $this->memcache->delete($memKey);
18272            }
18273            $addWelcomeModal = "&re_enrolled=1";
18274            return $this->redirect(myTools::getUrl() . "/mobapp/close?token=$apiToken&type=premium_plan_paid".$addWelcomeModal);
18275        }
18276
18277        // set view variables
18278        $this->set('cardLogo', myTools::getWorldpayCardLogo($userData['card_brand']));
18279        $this->set('apiToken', $apiToken);
18280        $this->set('cardBrand', $userData['card_brand']);
18281        $this->set('cardNumber', $userData['card_number']);
18282        $this->set('amount', $pData['amount']);
18283        $this->set('fAmount', $pData['fAmount']);
18284        $this->render(myTools::getDeviceUrl() . 'Payment/wp_credit_charge_confirm');
18285    }
18286    /**
18287     * @api {post} /mobapp/payment/credit_charge_confirm/:token 
18288     * @apiName mobapp_credit_charge_confirm
18289     * @apiGroup Payment
18290     * @apiDescription This endpoint is used to confirm the charging of the user's credit card.
18291     * 
18292     * @apiParam {String} token User's token
18293     * 
18294     * @apiBody {String} apiToken The API token.
18295     * @apiBody {String} cardToken The card token.
18296     * @apiBody {Object} ZPaymentFullLogs The payment full logs data.
18297     * @apiBody {Number} ZPaymentFullLogs.formType The form type. Set to 2 for force charge
18298     * @apiBody {Number} ZPaymentFullLogs.payment_plan_type The payment plan type.
18299     * @apiBody {Number} ZPaymentFullLogs.money The amount of money.
18300     * @apiBody {String} ZPaymentFullLogs.paymentHash The payment hash.
18301     * @apiBody {Object} discountOption The discount option data, if available.
18302     * @apiBody {Number} discountOption.amount The amount of the discount.
18303     * 
18304     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/close if payment is successful
18305     * 
18306     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if there is an error
18307     * @apiError {View} Redirect Redirects to {{ENV}}//mobapp/payment/failure_settlement if payment is not successful
18308     * 
18309     * @apiExample {json} Example usage:
18310     * {
18311     *       "apiToken": "api_token_12345",
18312     *       "cardToken": "card_token_12345",
18313     *       "ZPaymentFullLogs": {
18314     *             "formType": 2,
18315     *             "payment_plan_type": 1,
18316     *             "money": 1000,
18317     *             "paymentHash": "payment_hash_12345"
18318     *       },
18319     *       "discountOption": {
18320     *             "amount": 200
18321     *       }
18322      * }
18323     * 
18324     * @apiSuccessExample Success Response:
18325     * Redirects to {{ENV}}/mobapp/close
18326     * 
18327     * @apiErrorExample Error Response If there is an error:
18328     * Redirects to {{ENV}}/mobapp/retrypage
18329     * 
18330     * @apiErrorExample Error Response Payment Not Successful:
18331     * Redirects to {{ENV}}//mobapp/payment/failure_settlement
18332     * 
18333     * @apiSampleRequest off
18334     */
18335    public function mobapp_credit_charge_confirm() {
18336        $this->layout = 'mobapp';
18337        $formType = Configure::read('payment_credit_force_charge');
18338        $userData = $this->mobappGetUserData(array('logFileName' => 'card_charge', 'formType' => $formType)); // get user data and validate
18339        $userArr = $userData['User'];
18340        $apiToken = $this->request->query['token'];
18341        $isFreeFlg  = false;
18342        $freeNumber = $monthlyFee = 0;
18343        $basicFee = 0;
18344        $lessonLimit = 0;
18345        $corporateIndiUser = false;
18346        $indiCorpTypeLight = false;
18347        $corporatePaymentAmount = 0;
18348
18349        // redirect to retry page if memcache does not exist or expired
18350        if (!$data = $this->memcache->get('mobappUserCreditChargeInfo_'.$apiToken)) {
18351            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.myTools::getMobappToken($_GET));
18352        }
18353
18354        // if corporate user and retain individual plan
18355        if (isset($userArr['corporate_id'])) {
18356            $corporateIndiUser = true;
18357            // get coporate individual plan data
18358            if ($corporateChargeMemData = $this->memcache->get('mobappCreditChargeCorporateData_' . $userArr['id'])) {
18359                $fAmount = $corporateChargeMemData['fAmount'];
18360                $corporatePaymentAmount = $corporateChargeMemData['paymentAmount'];
18361                $isFreeFlg = isset($corporateChargeMemData['freeFlg']) ? $corporateChargeMemData['freeFlg'] : false;
18362                $freeNumber = isset($corporateChargeMemData['freeNumber']) ? $corporateChargeMemData['freeNumber'] : 0;
18363                $monthlyFee = isset($corporateChargeMemData['monthlyFee']) ? $corporateChargeMemData['monthlyFee'] : 0;
18364                $lessonLimit = isset($corporateChargeMemData['lessonLimit']) ? $corporateChargeMemData['lessonLimit'] : 0;
18365            }
18366
18367            if ($data['ZPaymentFullLogs']['indiCorpType'] == Configure::read('corporate_type.light')) {
18368                $indiCorpTypeLight = true;
18369            }
18370        } else {
18371            $fAmount = myTools::formatAmount($data['ZPaymentFullLogs']['money']);
18372        }
18373
18374        $readSkipConfirmation = true;// forcec skip to post
18375
18376
18377        if ($this->request->is('post') || $readSkipConfirmation) {
18378            // - set flag, on submission set 10 seconds delay / cooldown
18379            $this->memcache->set(array(
18380                'key' => 'creditChargePaymentSucess'.$userArr['id'],
18381                'value' => true,
18382                'expire' => 10
18383            ));
18384
18385            // check if token matches token in session
18386            $checkToken = $this->checkTokenMobapp($apiToken, $data['cardToken'], 'card-charge-');
18387
18388            // check if token is true
18389            if ($checkToken) {
18390
18391                // unset previously set tokens
18392                $this->unsetTokenMobapp($apiToken, 'card-charge-');
18393
18394                $formType = isset($data['ZPaymentFullLogs']['formType']) ? $data['ZPaymentFullLogs']['formType'] : $formType;
18395
18396                $isLitePlanUser = (isset($data['ZPaymentFullLogs']['payment_plan_type']) && (int) $data['ZPaymentFullLogs']['payment_plan_type'] == 1  ) ? true : false;
18397
18398                $isChocottoPlanUser = (
18399                    isset($data['ZPaymentFullLogs']['payment_plan_type']) &&
18400                    (int) $data['ZPaymentFullLogs']['payment_plan_type'] == Configure::read('register_plan_types.chocotto')
18401                );        
18402
18403                // if corporate credit charge
18404                if (
18405                    $formType != Configure::read('payment_credit_force_charge') && 
18406                    !$isLitePlanUser &&
18407                    !$isChocottoPlanUser
18408                ) {
18409                    $data['ZPaymentFullLogs']['money'] = $corporatePaymentAmount;
18410                }
18411
18412                if($corporateIndiUser) {
18413                    $data['ZPaymentFullLogs']['paymentHash'] = $this->memcache->get('indiCorpPaymentHash_'.$userArr['id']);
18414                }
18415
18416                $totalReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userArr['id']) + $this->PaymentReceivable->computeReceivableReservationPayment($userArr['id'], false, Configure::read('appreciation_data.payment_element_type')) + $this->PaymentReceivable->computeReceivableReservationPayment($userArr['id'], false, Configure::read('payment_element_type.live'));
18417
18418                $data['ZPaymentFullLogs']['money'] += $totalReceivable;
18419
18420                if (isset($data['discountOption'])) {
18421                    $data['ZPaymentFullLogs']['money'] -= $data['discountOption']['amount'];
18422                }
18423                $this->Session->write('mobapp_show_welcome_back_modal',true);
18424
18425                //process zeus card
18426                $this->zeus_card_process_mobapp(array(
18427                    'data' => $data,
18428                    'form_type' => $formType,
18429                    'referrer' => array('controller' => 'Payment', 'action' => 'mobapp_credit_charge', '?' => array('token' => $apiToken)),
18430                    'api_token' => $apiToken
18431                ));
18432
18433            } else {
18434                return $this->redirect(myTools::getUrl() . '/mobapp/payment/failure_settlement'.myTools::getMobappToken($_GET));
18435            }
18436        }
18437
18438        if (isset($data['ZPaymentFullLogs']['cardnumber']) && !empty($data['ZPaymentFullLogs']['cardnumber'])) {
18439            $cardNumberArr = str_split($data['ZPaymentFullLogs']['cardnumber'], 4);
18440            $this->set('cardNumber', end($cardNumberArr));
18441        } else {
18442            $this->getAndSetCardInfo($userData['User']);
18443        }
18444
18445        $this->set('corporateIndiUser', $corporateIndiUser);
18446        $this->set('corporateType', myTools::getCoporateTypeUsingPaymentPlanId($userArr['payment_plan_id']));
18447        $this->set('indiCorpTypeLight', $indiCorpTypeLight);
18448        $this->set('fAmount', $fAmount);
18449        $this->set('data', $data);
18450        $this->set('apiToken', $apiToken);
18451        $this->set('lessonLimit', $lessonLimit);
18452        $this->set('isFreeFlg', $isFreeFlg);
18453        $this->set('freeNumber', $freeNumber);
18454        $this->set('monthlyFee', $monthlyFee);
18455        $this->set('monthlyPriceSymbol', myTools::getCurrencySymbol($userArr['currency_code']));
18456        $this->render(myTools::getDeviceUrl() . 'Payment/credit_charge_confirm');
18457    }
18458    /**
18459     * @api {get} /mobapp/payment/paypal_payment_credit_charge_confirm/:token mobapp_paypal_credit_charge_confirm()
18460     * @apiName mobapp_paypal_credit_charge_confirm
18461     * @apiGroup Payment
18462     * @apiDescription This endpoint is used to confirm the charging of the user's credit card using PayPal.
18463     * 
18464     * @apiParam {String} token User's token
18465     * 
18466     * @apiSuccess {View} Render Displays the paypal credit charge confirm page.
18467     * 
18468     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if credit charge data does not exist / expired / no token.
18469     * 
18470     * @apiSuccessExample Success Response:
18471     * Render Displays the paypal credit charge confirm page.
18472     * 
18473     * @apiErrorExample Error Response:
18474     * Redirects to {{ENV}}/mobapp/retrypage
18475     * 
18476     * @apiSampleRequest off
18477     */
18478    public function mobapp_paypal_credit_charge_confirm() {
18479        $this->layout = 'mobapp';
18480        $logFileName = 'paypal_debug';
18481        $formType = Configure::read('payment_credit_force_charge');
18482
18483        // get user data and validate
18484        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType));
18485        $user = $userData['User'];
18486        $apiToken = $this->request->query['token'];
18487
18488        // redirect to retry page if data does not exist or expired
18489        if (!$data = $this->memcache->get('mobappPaypalPaymentCreditChargeData_' . $apiToken)) {
18490            $this->log(__METHOD__ . ' credit charge data does not exist or expired. user api token --> ' . json_encode($apiToken), $logFileName);
18491            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage' . myTools::getMobappToken($_GET));
18492        }
18493
18494        $this->set('paypalFlg', true); // use for modal loader
18495        $this->set('paypalUserData', $userData['User']);
18496        $this->set('fAmount', myTools::formatAmount($data['ZPaymentFullLogs']['money']));
18497        $this->set('monthlyPriceSymbol', myTools::getCurrencySymbol($user['currency_code']));
18498        $this->set('userApiToken', $apiToken);
18499
18500        // set payment gateway type
18501        $this->memcache->set(array(
18502            'key' => 'mobappCreditChargePaymentGatewayType_' . $apiToken,
18503            'value' => $data['payment_gateway_type'],
18504            'expire' => 3600 // 1 hour
18505        ));
18506
18507        $this->render(myTools::getDeviceUrl() . 'Payment/paypal_credit_charge_confirm');
18508    }
18509    /**
18510     * @api {get} /mobapp/payment/paypal_payment_credit_charge_process/:token/:payment_plan_type/:negativeTesting mobapp_paypal_credit_charge_process()
18511     * @apiName mobapp_paypal_credit_charge_process
18512     * @apiGroup Payment
18513     * @apiDescription This endpoint is used to process the charging of the user's credit card using PayPal.
18514     * 
18515     * @apiParam {String} token User's token
18516     * @apiParam {Number} payment_plan_type Payment plan type
18517     * @apiParam {Number} negativeTesting Indicates if negative testing is used on the transaction. 1 for true, 0 for false.
18518     * 
18519     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/close?token=$apiToken&type=premium_plan_paid&re_enrolled=1 if payment is successful.
18520     * 
18521     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if data does not exist or expired
18522     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/payment/credit_charge?token=$apiToken if light plan data does not exist
18523     * @apiError {View} Redirect Redirets to {{ENV}}/mobapp/retrypage if annual discount option does not exist or is not enabled
18524     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/payment/credit_charge?token=$apiToken if chocotto plan data does not exist
18525     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/payment/credit_charge?token=$apiToken if paypal payment is not successful
18526     * 
18527     * @apiSuccessExample Success Response:
18528     * Redirects to {{ENV}}/mobapp/close?token=$apiToken&type=premium_plan_paid&re_enrolled=1
18529     * 
18530     * @apiErrorExample Error Response Data does not exist or expired:
18531     * Redirects to {{ENV}}/mobapp/retrypage
18532     * 
18533     * @apiErrorExample Error Response Light plan data does not exist:
18534     * Redirects to {{ENV}}/mobapp/payment/credit_charge?token=$apiToken
18535     * 
18536     * @apiErrorExample Error Response Annual discount option does not exist or is not enabled:
18537     * Redirects to {{ENV}}/mobapp/retrypage
18538     * 
18539     * @apiErrorExample Error Response Chocotto plan data does not exist:
18540     * Redirects to {{ENV}}/mobapp/payment/credit_charge?token=$apiToken
18541     * 
18542     * @apiErrorExample Error Response Paypal payment is not successful:
18543     * Redirects to {{ENV}}/mobapp/payment/credit_charge?token=$apiToken
18544     *
18545     * @apiSampleRequest off
18546     */
18547    public function mobapp_paypal_credit_charge_process() {
18548        $this->autoRender = false;
18549        $this->layout = false;
18550
18551        $logFileName = 'paypal_debug';
18552        $formType = Configure::read('payment_credit_force_charge');
18553
18554        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType));
18555        $get = $this->request->query;
18556        $apiToken = $get['token'];
18557        $memKey = 'mobappPaypalPaymentCreditChargeData_' . $apiToken;
18558        $res = array('success' => false);
18559
18560        //- pass original payment plan
18561        $userObj = new UserTable($userData['User']);
18562        $userData['User']['original_status_index'] = $userObj->getMembershipTypeIndex();
18563
18564        // redirect to retry page if data does not exist or expired
18565        if (!$data = $this->memcache->get($memKey)) {
18566            $this->log(__METHOD__ . ' credit charge data does not exist or expired. user api token --> ' . json_encode($apiToken), $logFileName);
18567            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage' . myTools::getMobappToken($_GET));
18568        }
18569
18570        $paymentPlanType = isset($get['payment_plan_type']) ? $get['payment_plan_type'] : 0;
18571
18572        if ($paymentPlanType == Configure::read('register_plan_types.light')) {
18573            // fetch light plan description
18574            $litePlanData = $this->PaymentPlanPrice->getPaymentData(array(
18575                'currencyCode' => $userData['User']['currency_code'],
18576                'paymentPlanId' => Configure::read('payment_plans.light_plan'),
18577                'logFileName' => 'card_reregister'
18578            ));
18579
18580            if (!$litePlanData) {
18581                // set the memcache error
18582                $this->memcache->set(array(
18583                    'key' => 'card-error-'.$apiToken,
18584                    'value' => __("Error : 決済失敗"),
18585                    'expire' => 3600 // 1 hour
18586                ));
18587
18588                return $this->redirect('/mobapp/payment/credit_charge?token='.$apiToken);
18589            }
18590        
18591            $userData['User']['price_id'] = $litePlanData['priceId'];
18592            $userData['User']['payment_plan_id'] = $litePlanData['paymentPlanId'];
18593        
18594            // - update data 
18595            $data['paymentPlanData'] = $litePlanData;
18596            $data['formType'] =  myTools::getLitePlanUserFormType($litePlanData['paymentPlanId']);
18597
18598        } elseif ($paymentPlanType == Configure::read('register_plan_types.premium_with_annual_discount_option')) {
18599            $annualDiscountOptionData = $this->DiscountOptionsPrice->getPaymentData(['currencyCode' => $userData['User']['currency_code'], 'discountOptionId' => Configure::read('discount_option.annual.plan_id')]);
18600
18601            // redirect to credit page if annual discount option does not exist or is not enabled
18602            if (!$annualDiscountOptionData) {
18603                return $this->redirect(myTools::getUrl() . '/mobapp/retrypage' . myTools::getMobappToken($_GET));
18604            }
18605
18606            unset($annualDiscountOptionData['contract_start']);
18607            $annualDiscountOptionData += [
18608                'dosh_event' => Configure::read('discount_option.dosh_event.annual_discount'),
18609                'dosh_status' => Configure::read('discount_option.dosh_status.monthly_discount')
18610            ];
18611
18612            // update payment transaction (add annual discount option data)
18613            $this->PaymentTransaction->updatePaymentParams(array('paymentHash' => $data['ZPaymentFullLogs']['paymentHash'], 'updateData' => ['annualDiscountOption' => $annualDiscountOptionData]));
18614
18615            $data['discountOption'] = $annualDiscountOptionData;
18616
18617        //- NJ-27262 chocotto plan    
18618        } elseif ($paymentPlanType == Configure::read('register_plan_types.chocotto')) {
18619            // fetch chocotto plan description
18620            $chocottoPlanData = $this->PaymentPlanPrice->getPaymentData(array(
18621                'currencyCode' => $userData['User']['currency_code'],
18622                'paymentPlanId' => Configure::read('payment_plans.chocotto_plan'),
18623                'logFileName' => 'card_reregister'
18624            ));
18625
18626            if (!$chocottoPlanData) {
18627                // set the memcache error
18628                $this->memcache->set(array(
18629                    'key' => 'card-error-'.$apiToken,
18630                    'value' => __("Error : 決済失敗"),
18631                    'expire' => 3600 // 1 hour
18632                ));
18633
18634                return $this->redirect('/mobapp/payment/credit_charge?token='.$apiToken);
18635            }
18636        
18637            //- NJ-36141: reset daily lesson time if changed to chocotto plan
18638            $this->UsersDetail->chocottoCampUserDetails($userData['User']['id'], true);
18639            
18640            $userData['User']['price_id'] = $chocottoPlanData['priceId'];
18641            $userData['User']['payment_plan_id'] = $chocottoPlanData['paymentPlanId'];
18642        
18643            // - update data
18644            $data['paymentPlanData'] = $chocottoPlanData;
18645            $data['formType'] = Configure::read('payment_credit_chocotto_force_charge');
18646        }
18647
18648        // NJ-32737
18649        $couponData = $this->Session->read('apply_coupon_usage_data');
18650
18651        if (!empty($couponData['useCouponAmount'])) {
18652            $data['couponUseSettlement'] = $couponData;
18653        }
18654
18655        if ((isset($get['negativeTesting']) && $get['negativeTesting']) || !$this->processPayPalPayment($data, $userData['User'])) {
18656            // set the memcache error
18657            $this->memcache->set(array(
18658                'key' => 'card-error-'.$apiToken,
18659                'value' => __("Error : 決済失敗"),
18660                'expire' => 3600 // 1 hour
18661            ));
18662
18663            return $this->redirect('/mobapp/payment/credit_charge?token='.$apiToken);
18664        }
18665
18666        $memKey = 'mobappCreditChargePaymentGatewayType_' . $apiToken;
18667
18668        // delete memcache payment gateway type
18669        if ($this->memcache->get($memKey)) {
18670            $this->memcache->delete($memKey);
18671        }
18672
18673        $this->memcache->delete('mobappUserCreditChargeInfo_'.$apiToken);
18674        return $this->redirect(array('controller' => 'Mobapp', 'action' => 'close', '?' => array('token' => $apiToken, 'type' => 'premium_plan_paid','re_enrolled' => 1)));
18675    }
18676
18677    /**
18678    * [addTransaction add payment transaction for mobapp]
18679    * @param array - user data
18680    * @return array - result - transaction password
18681    */
18682    private function mobappSetUpTransaction($formType = null, $paymentData = array()) {
18683        $pt = array();
18684
18685        switch ($formType) {
18686            case Configure::read('payment_credit_retry'):
18687                $logFileName = 'card_retry';
18688                break;
18689            case Configure::read('payment_credit_authentication'):
18690                $logFileName = 'card_registration';
18691                break;
18692            case Configure::read('payment_credit_force_charge'):
18693                $logFileName = 'card_charge';
18694                break;
18695            case Configure::read('payment_credit_change'):
18696                $logFileName = 'card_change';
18697                break;
18698            default:
18699                $logFileName = 'debug';
18700        }
18701
18702        if (!$formType) {
18703            $this->log(__METHOD__ . ' form type does not exist. ' . json_encode($formType), $logFileName);
18704            return $pt;
18705        }
18706
18707        if (!isset($paymentData['payment_plan_id']) && !isset($paymentData['paymentPlanId'])) {
18708            $this->log(__METHOD__ . ' missing parameter payment plan id. ' . json_encode($paymentData), $logFileName);
18709            return $pt;
18710        }
18711
18712        if (!isset($paymentData['price_id']) && !isset($paymentData['priceId'])) {
18713            $this->log(__METHOD__ . ' missing parameter price id. ' . json_encode($paymentData), $logFileName);
18714            return $pt;
18715        }
18716
18717
18718
18719        // set payment transactions
18720        $pt = $this->PaymentTransaction->setPaymentTransaction(array(
18721            'user_id' => $user['id'],
18722            'payment_hash' => $user['hash16'],
18723            'course_id' => Configure::read("credit.course_id")
18724        ));
18725
18726        // check if payment transaction exists
18727        if ($pt) {
18728            $result = array(
18729                'password' => isset($pt['password'])? $pt['password'] : null
18730            );
18731        }
18732
18733        // return password
18734        return isset($pt['password'])? $result['password'] : null;
18735    }
18736
18737    /**
18738    * check token for mobapp
18739    * @param apiToken - users api token, cardToken - token created when selecting card, key - key used to retrieve memcache cardToken
18740    * @return boolean
18741    */
18742    private function checkTokenMobapp($apiToken = null, $cardToken = null, $key = null){
18743        $cacheToken = $this->memcache->get($key.$apiToken);
18744        return ($cacheToken === $cardToken);
18745    }
18746
18747    /**
18748    * unset previously set card tokens memcache for mobapp
18749    */
18750    private function unsetTokenMobapp($apiToken = null, $key = null) {
18751        $cardToken = $this->memcache->get($key.$apiToken);
18752        if ($cardToken) {
18753            $this->memcache->delete($key.$apiToken);
18754        }
18755        return;
18756    }
18757
18758    /**
18759    * get users data using api token
18760    * @param token string
18761    * @return array - user data
18762    */
18763    private function getUserData($token) {
18764        $this->User->recursive = -1;
18765        $userData = $this->User->useReplica()->find('first', array(
18766            'joins' => array(
18767                array(
18768                    'table' => 'payment_svc_prices',
18769                    'alias' => 'PaymentPlanPrice',
18770                )
18771            ),
18772            'conditions' => array('User.api_token' => $token)
18773        ));
18774        return $userData ? $userData : false;
18775    }
18776
18777    /**
18778    * process zeus card 
18779    */
18780    private function zeus_card_process_mobapp($params = array()){
18781        $this->autoRender = false;
18782        //data
18783        $data = isset($params['data']) ? $params['data'] : null;
18784        $formType = isset($params['form_type']) ? $params['form_type'] : null;
18785        $referrer = isset($params['referrer']) ? $params['referrer'] : null;
18786        $apiToken = isset($params['api_token']) ? $params['api_token'] : null;
18787        $cardToken = isset($params['card_token']) ? $params['card_token'] : null;
18788        $paymentHash = isset($params['paymentHash']) ? $params['paymentHash'] : null;
18789        $urlRedirect = isset($data['page_origin']) ? $data['page_origin'] : null;
18790        $fromUnliOption = isset($params['unli_option']) ? $params['unli_option'] : null;
18791        $isLitePlanUser = (isset($params['isLitePlanUser']) && !empty($params['isLitePlanUser']));
18792
18793        $this->User->recursive = -1;
18794        $this->User->openDBReplica();
18795        // $userData = $this->User->findByApiToken($apiToken);
18796        $userData = $this->User->find('first', array(
18797            'fields' => array(
18798                'User.id',
18799                'User.email',
18800                'User.complimentary_code',
18801                'User.currency_code',
18802                'User.corporate_type'
18803            ),
18804            'conditions' => array(
18805                'User.api_token' => $apiToken
18806            ),
18807            'recursive' => -1
18808        ));
18809        $this->User->closeDBReplica();
18810
18811        if (!$userData) {
18812            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.myTools::getMobappToken($_GET));
18813        }
18814        
18815        // user
18816        $user = new UserTable($userData['User']);
18817
18818        $modelname ="ZPaymentFullLogs";
18819        $this->set(compact("modelname"));
18820
18821        $checkReregisterSession = $this->Session->read('mobapp_show_welcome_back_modal');
18822        if ($checkReregisterSession) {
18823            $this->Session->delete('mobapp_show_welcome_back_modal');
18824        }
18825
18826        // - if maintenance and mobapp process redirect
18827        if (myTools::zeusMaintenancePeriod()) {
18828            return $this->redirect(myTools::getUrl() . '/mobapp/payment/failure_settlement'.myTools::getMobappToken($_GET));
18829        }
18830
18831        if ($data) {
18832            switch ($formType) {
18833                case Configure::read('payment_credit_retry'):
18834                case Configure::read('payment_credit_chocotto_retry'):
18835                    // NC-7029 coupon discount
18836                    if (isset($data[$modelname]['discounted_amount'])) {
18837                        if ($data[$modelname]['money'] <= $data[$modelname]['discounted_amount']) {
18838                            $data[$modelname]['discounted_amount'] = $data[$modelname]['money'];
18839                            $data[$modelname]['money'] = 0;
18840                        } else {
18841                            $data[$modelname]['money'] -= $data[$modelname]['discounted_amount'];
18842                        }
18843                    }
18844                case Configure::read('payment_credit_force_charge'):
18845                case Configure::read('payment_individual_corporate_standard'):
18846                case Configure::read('payment_individual_corporate_premium'):
18847                case Configure::read('payment_prepaid_corporate_light_member'):
18848                case Configure::read('payment_lite_credit_paid'):
18849                case Configure::read('payment_credit_chocotto_monthly_payment'):
18850                case Configure::read('payment_credit_chocotto_force_charge'):
18851                    $money = $data[$modelname]['money'];
18852                    break;
18853                case Configure::read('payment_credit_change'):
18854                case Configure::read('corporate_credit_card_registration'):
18855                    // get reserve payment receivable
18856                    $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($user->id);
18857
18858                    // get appreciation payment receivable
18859                    $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($user->id, false, Configure::read('appreciation_data.payment_element_type'));
18860
18861                    // get live lesson payment receivable
18862                    $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($user->id, false, Configure::read('payment_element_type.live'));
18863
18864                    $money = $receivablePayment + $appreciationReceivable + $liveLessonReceivable;
18865                    break;
18866                case Configure::read('payment_credit_authentication'):
18867                case Configure::read('payment_lite_credit_free'):
18868                case Configure::read('payment_credit_chocotto_free'):    
18869                    $money = 0;
18870                    break;
18871                default:
18872                    $money = 0;
18873                    $formType = Configure::read('payment_credit_default');
18874                    break;
18875            }
18876            
18877            $pData = array(
18878                'clientIp' => (int) $data[$modelname]['clientip'],
18879                'cardNumber' => isset($data[$modelname]['cardnumber']) ? (int) $data[$modelname]['cardnumber'] : '',
18880                'expyy' => isset($data[$modelname]['expyy']) ? (int) $data[$modelname]['expyy'] : 0,
18881                'expmm' => isset($data[$modelname]['expmm']) ? (int) $data[$modelname]['expmm'] : 0,
18882                'telNo' => (int) $data[$modelname]['telno'],
18883                'email' => $user->email,
18884                'username' => isset($data[$modelname]['username']) ? mb_strtoupper($data[$modelname]['username']) : '',
18885                'sendId' => $user->id,
18886                'money' => $money,
18887                'tokenKey' => isset($data[$modelname]['zeusTokenValue']) ? $data[$modelname]['zeusTokenValue'] : '',
18888                'paymentHash' => $data[$modelname]['paymentHash']
18889            );
18890
18891            // send curl request
18892            if (isset($data['zeus_card_option']) && $data['zeus_card_option'] == "prev") {
18893                $res = ZChargeComponent::charge_with_regsterd_card(json_encode($pData));
18894            } else {
18895
18896                // update payment params -  add card expiration date
18897                if (isset($data[$modelname]['expyy']) && isset($data[$modelname]['expmm'])) {
18898                    $paymentParamsData = array('cardExpirationDate' => date('Y-m-t', strtotime($data[$modelname]['expyy'] . '-' . $data[$modelname]['expmm'])));
18899                    $this->PaymentTransaction->updatePaymentParams(array('paymentHash' => $data[$modelname]['paymentHash'], 'updateData' => $paymentParamsData));
18900                }
18901
18902                // get zeus challenge flag
18903                $zeus3DSecureChallengeFlg = $this->memcache->get('zeus3DSecureChallengeFlg_' . $user->id);
18904                // NJ-25522: payment was charged after challenge already
18905                if ($zeus3DSecureChallengeFlg) {
18906                    $zeus3DSecurePaymentSuccessFlg = $this->memcache->get('zeus3DSecurePaymentSuccessFlg_' . $user->id);
18907                    $res = !empty($zeus3DSecurePaymentSuccessFlg) && $zeus3DSecurePaymentSuccessFlg == 'OK' ? 'Success_order' : 'failure_order';
18908                    // clear flag
18909                    $this->memcache->delete('zeus3DSecureChallengeFlg_' . $user->id);
18910                    $this->memcache->delete('zeus3DSecurePaymentSuccessFlg_' . $user->id);
18911
18912                // default process without challenge, charge directly
18913                } else {
18914                    $res = $this->ZCharge->charge_regist(json_encode($pData));
18915                }
18916            }
18917
18918            // if successful
18919            if ( $res[0] == "Success_order" || $res == "Success_order") {
18920                if ($formType == Configure::read('payment_credit_authentication')) {
18921                    // send registration completion email
18922                    App::uses('myMailer','Lib');
18923                    $mail_id = Configure::read('site_in_mail.student_registration_complete');
18924                    if ($userData &&  !in_array($userData['User']['currency_code'], Configure::read('global_free_trail_currencies') ) ) {
18925                        $mail_id = Configure::read('site_in_mail.registration_no_trial_currencies');
18926                    }
18927                    myMailer::sendTemplateMail($mail_id, $userData['User']['email'], $userData['User'], array(), 'User');
18928                    $this->Session->write('reenroll_native_option', true);
18929                    return $this->redirect(array('controller' => 'Payment', 'action' => 'mobapp_credit_register_notice_to_user', '?' => array('token' => $apiToken, 'cardToken' => $cardToken)));
18930                } else if (
18931                    $formType == Configure::read('payment_credit_force_charge') ||
18932                    $formType == Configure::read('payment_lite_credit_paid') ||
18933                    $formType == Configure::read('payment_credit_chocotto_monthly_payment') ||
18934                    $formType == Configure::read('payment_credit_chocotto_force_charge')
18935                ) {
18936
18937                    // - set flag
18938                    $this->memcache->set(array(
18939                        'key' => 'creditChargePaymentSucess'.$user->id,
18940                        'value' => true,
18941                        'expire' => 30 // 30 sec
18942                    ));
18943
18944                    $this->memcache->delete('mobappUserCreditChargeInfo_'.$apiToken);
18945                    $_addParams = array(
18946                        'token' => $apiToken
18947                    );
18948                    if ($checkReregisterSession) {
18949                        $_addParams = array(
18950                            'token' => $apiToken,
18951                            're_enrolled' => 1
18952                        );
18953                    }
18954
18955                    if ($formType == Configure::read('payment_lite_credit_paid')) {
18956                        $this->liteUserAddCoinRewardForReenroll(array('id' => $user->id));
18957                    }
18958
18959                    if (isset($user->complimentary_code) && $this->memcache->get('com_plan_user_' . $user->id)) {
18960                        $this->memcache->delete('com_plan_user_' . $user->id);
18961                        $_addParams['type'] = 'special_complimentary_plan';
18962                        return $this->redirect(array('controller' => 'Mobapp', 'action' => 'close', '?' => $_addParams));
18963                    } else {
18964                        $_addParams['type'] = 'premium_plan_paid';
18965                        $_addParams['re_enrolled'] = 1;
18966                        return $this->redirect(array('controller' => 'Mobapp', 'action' => 'close', '?' => $_addParams));
18967                    }
18968                } else if ($formType == Configure::read('payment_credit_change')) {
18969                    if ($urlRedirect) {
18970                        $urlParams = "?token=".$apiToken;
18971                        if ( $urlRedirect == 2 ) { // ebook
18972                            $urlParams = $urlParams."&new_card=ebook";
18973                        }
18974                        return $this->redirect(myTools::getUrl() . '/mobapp/store/card_register_complete' . $urlParams );
18975                    } else {
18976                        $_addParams = array(
18977                            'token' => $apiToken,
18978                            'type' => 'card_change'
18979                        );
18980
18981                        if (isset($fromUnliOption) && !empty($fromUnliOption) && $fromUnliOption==1){
18982                            return $this->redirect(myTools::getUrl() . '/mobapp/option/native-start' . '?token='.$apiToken . '&unli_option='.$fromUnliOption);
18983                        } else {
18984                            return $this->redirect(array('controller' => 'Mobapp', 'action' => 'close', '?' => $_addParams));
18985                        }
18986                    }
18987                } else if ($formType == Configure::read('payment_credit_retry')) {
18988                    // - flag manual paying user sucess
18989                    UserTable::saveManualPayingUsersToMemcache($user->id);
18990                    $this->memcache->delete('mobappUserCreditRetryInfo_'.$apiToken);
18991                        $_addParams = array(
18992                            'token' => $apiToken,
18993                            'type' => 'credit_retry_complete'
18994                        );
18995                        if ($checkReregisterSession) {
18996                            $_addParams['re_enrolled'] = 1;
18997                        }
18998
18999                    return $this->redirect(array('controller' => 'Payment', 'action' => 'mobapp_credit_retry_complete', '?' => $_addParams));
19000                } else if (
19001                    $formType == Configure::read('payment_individual_corporate_standard') ||
19002                    $formType == Configure::read('payment_individual_corporate_premium') ||
19003                    $formType == Configure::read('payment_prepaid_corporate_light_member')
19004                ) {
19005                    if ($this->memcache->get('mobappCreditChargeCorporateData_' . $user->id)) {
19006                        $this->memcache->delete('mobappCreditChargeCorporateData_' . $user->id);
19007                    }
19008
19009                    $_addParams = array(
19010                        'token' => $apiToken,
19011                    );
19012
19013                    if ($checkReregisterSession) {
19014                        $_addParams['re_enrolled'] = 1;
19015                    }
19016
19017
19018                    // Credit charge
19019                    if ( $this->memcache->get('mobappUserCreditChargeInfo_'.$apiToken) ) {
19020                        $_addParams['type'] = 'corporate_light_plan';
19021                        $this->memcache->delete('mobappUserCreditChargeInfo_'.$apiToken);
19022                    }
19023                    // Credit retry
19024                    if ( $this->memcache->get('mobappUserCreditRetryInfo_'.$apiToken) ) {
19025                        // - flag manual paying user sucess
19026                        UserTable::saveManualPayingUsersToMemcache($user->id);
19027                        $this->memcache->delete('mobappUserCreditRetryInfo_'.$apiToken);
19028                        $_addParams['type'] = 'credit_retry_complete';
19029                        
19030                    }
19031
19032                    // NJ-33414 Update User's Lesson Request to Default
19033                    $this->UsersDetail->openDBReplica();
19034                    $usersDetail = $this->UsersDetail->find('first', array(
19035                        'fields' => array('lesson_request_flg'),
19036                        'conditions' => array('UsersDetail.user_id' => $userData['User']['id']),
19037                        'recursive' => -1
19038                    ));
19039                    $this->UsersDetail->closeDBReplica();
19040
19041                    if( $usersDetail ) {
19042                        $this->UsersDetail->clear();
19043                        $this->UsersDetail->query("
19044                                UPDATE
19045                                    `users_detail`
19046                                SET
19047                                    `lesson_request_flg` = 1
19048                                WHERE
19049                                    `user_id` = {$userData['User']['id']}
19050                        ");
19051                    } else {
19052                        $this->UsersDetail->clear();
19053                        $this->UsersDetail->set([
19054                            'user_id' => $userData['User']['id'],
19055                            'individual_card_fail_flg'    => 0,
19056                            'lesson_request_flg' => 1
19057                        ]);
19058                        $this->UsersDetail->validate = [];
19059                        $this->UsersDetail->save();
19060                    }
19061                    
19062                    if ($this->memcache->get('mobappcorporateIndiPrices_' . $apiToken)) {
19063                        $this->memcache->delete('mobappCcorporateIndiPrices_' . $apiToken);
19064                    }
19065                                        
19066                    return $this->redirect(array('controller' => 'Mobapp', 'action' => 'close', '?' => $_addParams));
19067                } else {
19068                    return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.myTools::getMobappToken($_GET));
19069                }
19070            } else {
19071                // handle errors
19072                $this->handleCreditResponseErrorMobapp(array(
19073                    'res' => $res, 
19074                    'referrer' => $referrer,
19075                    'api_token' => $apiToken
19076                ));
19077            }
19078        }
19079    }
19080
19081    // catch errors for mobapp
19082    private function handleCreditResponseErrorMobapp($params = array()){
19083        //data
19084        $res = isset($params['res']) ? $params['res'] : null;
19085        $referrer = isset($params['referrer']) ? $params['referrer'] : null;
19086        $apiToken = isset($params['api_token']) ? $params['api_token'] : null;
19087
19088        // errors
19089        $error = "";
19090        $failureOrder = "failure_order";
19091        $maintenance = "maintenance";
19092        $connectError = "connect error";
19093        $cardNumberError = "Invalid Cardnumber";
19094        $telnoError = "Invalid telno";
19095        $usernameError = "Invalid username";
19096        $invalidClientIp = "Invalid clientip";
19097
19098        // check error message
19099        if ($res[0] == $failureOrder || $res == $failureOrder) {
19100            $error = __("Error : 決済失敗");
19101        } else if ($res[0] == $maintenance || $res == $maintenance) {
19102            $error = __("Error : メンテナンス中");
19103        } else if ($res[0] == $connectError || $res == $connectError) {
19104            $error = __("Error : Connect Error");
19105        } else if ($res[0] == $cardNumberError || $res == $cardNumberError) {
19106            $error = __("Error : カード番号が正しくありません 半角数字で入力してください。ハイフン(-)は必要ありません。");
19107        } else if ($res[0] == $telnoError || $res == $telnoError) {
19108            $error = __("Error : 電話番号が正しくありません 半角数字で入力してください。ハイフン(-)は必要ありません。");
19109        } else if ($res[0] == $usernameError || $res == $usernameError) {
19110            $error = __("Error : クレジットカードに記載されている名前を半角英字で入力してください。");
19111        } else if ($res[0] == $invalidClientIp || $res == $invalidClientIp) {
19112            $error = __("Error : 決済失敗");
19113        } else {
19114            $error = $res;
19115        }
19116
19117        // set the memcache error
19118        $this->memcache->set(array(
19119            'key' => 'card-error-'.$apiToken,
19120            'value' => $error,
19121            'expire' => 3600
19122        ));
19123
19124        //redirect to credit card select
19125        return $this->redirect($referrer);
19126    }
19127    /**
19128     * @api {get} /:language/payment/failure_family failure_family()
19129     * @apiName failure_family
19130     * @apiGroup Payment
19131     * @apiDescription This endpoint is used to display failure family page.
19132     * 
19133     * @apiParam {String} language Language code (ja/en).
19134     * 
19135     * @apiSuccess {View} Render Renders the failure family page.
19136     * @apiSuccess {View} Render Renders the failure family page sp version for mobile
19137     * 
19138     * @apiSuccessExample Success Response PC:
19139     * Renders the failure family page.
19140     * 
19141     * @apiSuccessExample Success Response Mobile:
19142     * Renders the failure family page sp version for mobile.
19143     * 
19144     * @apiSampleRequest off
19145     */
19146    public function failure_family() {
19147        if ($this->RequestHandler->isMobile()) {
19148            $this->sp_failure_family();
19149        }
19150    }
19151    
19152    public function sp_failure_family(){
19153        $this->layout = "mobile";
19154        $this->render('/Mobile/Payment/failure_family');
19155    }
19156
19157    /**
19158     * Get user id from zeuspay kickback data
19159     * @param array $data
19160     * @return int $userId
19161    */
19162    private function getUserId($data = null) {
19163        $userId = 0;
19164        if ($data) {
19165            // check if sendpoint and sendid are exist
19166            if (isset($data['sendpoint']) && $data['sendpoint'] && isset($data['sendid']) && $data['sendid']) {
19167                $sendPoint = $this->decodeSendPointData($data['sendpoint']);
19168                // family plan user
19169                $formTypes = array(
19170                    Configure::read('payment_credit_family_monthly_payment'),
19171                    Configure::read('payment_credit_coin_purchase'),
19172                    Configure::read('payment_credit_textbook_purchase'),
19173                    Configure::read('payment_credit_fund'),
19174                    Configure::read('payment_credit_receivable')
19175                );
19176                if (
19177                    isset($sendPoint['formType']) && in_array($sendPoint['formType'], $formTypes) 
19178                    && isset($sendPoint['familyId']) && $sendPoint['familyId']
19179                ) {
19180                    $userId = $sendPoint['familyId'];
19181                } else {
19182                    $userId = $data['sendid'];
19183                }
19184            }
19185        }
19186        return $userId;
19187    }
19188
19189    /**
19190    * decode sendPoint data from kickback
19191    * @return array
19192    */
19193    private function decodeSendPointData($args = null) {
19194        $this->log(__METHOD__ . json_encode($args), 'debug');
19195        $sendPointKeyEquiv = array(
19196            'r' => 'remoteAddress',
19197            'p' => 'paymentType',
19198            'm' => 'formType',
19199            'w' => 'password',
19200            'f' => 'familyId',
19201            't' => 'platform',
19202            'd' => 'cronDateRun' // hotfix_NC-3152
19203        );
19204
19205        $arrData = array();
19206        $data = '';
19207        if ($args) {
19208            $break = explode('|', $args);
19209            for ($i=0; $i<count($break); $i++) {
19210                unset($data);
19211                $data = explode(':', $break[$i]);
19212                if ($data) {
19213                    $index = $sendPointKeyEquiv[$data[0]];
19214                    $arrData[$index] = isset($data[1]) ? $data[1] : '';
19215                }
19216            }
19217        }
19218        return $arrData;
19219    }
19220    /**
19221     * @api {get} /mobapp/payment/failure_family/:token failureFamily()
19222     * @apiName failureFamily
19223     * @apiGroup Payment
19224     * @apiDescription This endpoint is used to display failure family page.
19225     * 
19226     * @apiParam {String} token User's api token.
19227     * 
19228     * @apiSuccess {View} Render Renders the failure family page.
19229     * 
19230     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if token / user does not exist.
19231     * 
19232     * @apiSuccessExample Success Response:
19233     * Renders the failure family page.
19234     * 
19235     * @apiErrorExample Error Response:
19236     * Redirects to {{ENV}}/mobapp/retrypage if token / user does not exist.
19237     * 
19238     * @apiSampleRequest off
19239     */
19240    public function failureFamily() {
19241        $this->layout = "mobapp";
19242        // get $_GET url paramters
19243        $getParams = $this->params->query;
19244
19245        if (empty($getParams['token'])) {
19246            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.myTools::getMobappToken($_GET));
19247        }
19248
19249        $data =  $this->User->find('count',array(
19250            'conditions' => array('User.api_token' => $getParams['token']),
19251            'recursive' => -1
19252        ));
19253
19254        if (!$data) {
19255            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.myTools::getMobappToken($_GET));
19256        }
19257        $this->set('token', $getParams['token']);
19258        $this->set('title_for_layout', '退会手続き');
19259        $this->render(myTools::getDeviceUrl() . 'Payment/failure_family');
19260    }
19261
19262    /**
19263     * NC-3914: get user card number and card logo and use it in view.
19264     * @param array $userData
19265     */
19266    public function getAndSetCardInfo($userData = array()) {
19267        $cardInfo = '';
19268        if ($userData) {
19269            $cardNumber = $userData['card_number'];
19270            $cardBrand = $userData['card_brand'];
19271            if (
19272                (is_null($cardNumber) || is_null($cardBrand)) &&
19273                !isset($userData['corporate_id']) && !isset($userData['payment_plan_id'])
19274            ) {
19275                // get user last successful payment card info.
19276                $cardInfo = $this->Payment->getUserCardInfo($userData['id']);
19277                $cardNumber = isset($cardInfo['cardNumber']) ? $cardInfo['cardNumber'] : null;
19278                $cardBrand = isset($cardInfo['cardBrand']) ? $cardInfo['cardBrand'] : null;
19279            }
19280        }
19281
19282        // get card logo
19283        $cardLogos = array(
19284            'A' => 'logo_americanexpress.png',
19285            'D' => 'logo_dinersclub.png',
19286            'J' => 'logo_jcb.png',
19287            'M' => 'logo_mastercard.png',
19288            'V' => 'Icon_visa.png',
19289            'P' => 'Icon_paypal.png',
19290            'TEST' => 'Icon_visa.png'
19291        );
19292
19293        $cardBrands = array(
19294            'A' => 'AMERICAN EXPRESS',
19295            'D' => 'DINERS CLUB',
19296            'J' => 'JCB',
19297            'M' => 'MASTERCARD',
19298            'V' => 'VISA',
19299            'P' => 'PAYPAL',
19300            'TEST' => 'VISA'
19301        );
19302
19303        $this->set('cardNumber', isset($cardNumber) && !empty($cardNumber) ? $cardNumber : null);
19304        $this->set('cardLogo', isset($cardLogos[$cardBrand]) ? $cardLogos[$cardBrand] : null);
19305        $this->set('cardBrand', isset($cardBrands[$cardBrand]) ? $cardBrands[$cardBrand] : null);
19306    }
19307
19308    /**
19309     * NC-3914: check if user_new_card_info session exist
19310     * if exist then set view vars
19311     * delete session
19312     */
19313    private function setPaymentViewVars() {
19314        $userCardInfo = $this->Session->read('user_new_card_info');
19315        if ($userCardInfo) {
19316            $this->set('data', $userCardInfo);
19317            $this->Session->delete('user_new_card_info');
19318        }
19319    }
19320    /**
19321     * @api {get} /:language/payment/failure_settlement failure_settlement()
19322     * @apiName failure_settlement
19323     * @apiGroup Payment
19324     * @apiDescription This endpoint is used to display failure settlement page.
19325     * 
19326     * @apiParam {String} language Language code.
19327     * 
19328     * @apiSuccess {View} Render Renders the failure settlement page.
19329     * @apiSuccess {View} Render Renders the failure settlement sp page
19330     * 
19331     * @apiSuccessExample Success Response PC:
19332     * Renders the failure settlement page.
19333     * 
19334     * @apiSuccessExample Success Response Mobile:
19335     * Renders the failure settlement sp page.
19336     * 
19337     * @apiSampleRequest off
19338     */
19339    public function failure_settlement(){
19340        if ($this->RequestHandler->isMobile()) {
19341            $this->sp_failure_settlement();
19342        }
19343    }
19344    /**
19345     * @api {get} /mobapp/payment_failure_settlement/:token/:referer mobapp_failure_settlement()
19346     * @apiName mobapp_failure_settlement
19347     * @apiGroup Payment
19348     * @apiDescription This endpoint is used to display failure settlement page.
19349     * 
19350     * @apiParam {String} token User's api token.
19351     * @apiParam {String} referer Referer url.
19352     * 
19353     * @apiSuccess {View} Render Renders the failure settlement page.
19354     * 
19355     * @apiSuccessExample Success Response:
19356     * Renders the failure settlement page.
19357     * 
19358     * @apiSampleRequest off
19359     */
19360    public function mobapp_failure_settlement(){
19361        $token = !empty($this->request->query['token']) ? $this->request->query['token'] : "";
19362        $type = !empty($this->request->query['type']) ? $this->request->query['type'] : "";
19363        $fromPage = !empty($this->request->query['from_page']) ? $this->request->query['from_page'] : "";
19364        $unliOption = !empty($this->request->query['unli_option']) ? $this->request->query['unli_option'] : "";
19365        $referer = !empty($this->request->query['referer']) ? $this->request->query['referer'] : myTools::getUrl() . "/mobapp/payment/credit_change?token=" . $token;
19366
19367        $this->set('fromPage', $fromPage);
19368        $this->set('unliOption', $unliOption);
19369        $this->set('token', $token);
19370        $this->set('type', $type);
19371        $this->set('referer', $referer);
19372        $this->layout = "mobapp";
19373        $this->render(myTools::getDeviceUrl() . 'Payment/failure_settlement');
19374    }
19375    
19376    public function sp_failure_settlement(){
19377        $type = !empty($this->request->query['type']) ? $this->request->query['type'] : "";
19378        $fromPage = !empty($this->request->query['from_page']) ? $this->request->query['from_page'] : "";
19379        $unliOption = !empty($this->request->query['unli_option']) ? $this->request->query['unli_option'] : "";
19380        
19381        $this->set('type', $type);
19382        $this->set('fromPage', $fromPage);
19383        $this->set('unliOption', $unliOption);
19384        $this->layout = "mobile";
19385        $this->render('/Mobile/Payment/failure_settlement');
19386    }
19387
19388    /**
19389    * NC-4770:  Worldpay get users data using api token
19390    * @param string $token
19391    * @return array $data
19392    */
19393    private function getWPUserData($token) {
19394        $data = $this->User->useReplica->find('first', array(
19395            'fields' => array(
19396                'User.id',
19397                'User.email',
19398                'SettlementCurrency.currency'
19399            ),
19400            'joins' => array(
19401                array(
19402                    'table' => 'settlement_currency',
19403                    'alias' => 'SettlementCurrency',
19404                    'type' => 'LEFT',
19405                    'conditions' => 'SettlementCurrency.id = User.settlement_currency_id'
19406                )
19407            ),
19408            'conditions' => array('User.api_token' => $token),
19409            'recursive' => -1
19410        ));
19411
19412        return $data ? $data : array();
19413    }
19414
19415    /**
19416     * NC-4770: Worldpay common method for updating user's payment transaction
19417     * @param array $params
19418     * @return array $result
19419     */
19420    public function updatePaymentTransaction($params = array()) {
19421        $logFileName = isset($params['logFileName']) ? $params['logFileName'] : 'debug';
19422        $result = array();
19423        if (
19424            !empty($params['id']) && isset($params['fields']) && !empty($params['logFileName'])
19425        ) {
19426            $updateData = array(
19427                'id' => $params['id'],
19428                'fields' => $params['fields']
19429            );
19430
19431            $result = $this->PaymentTransaction->updateWPPaymentTransaction($updateData);
19432        }
19433
19434        if (!$result) {
19435            $this->log(__METHOD__ .' Failed to update payment transaction. update data --> ' . json_encode($params), $logFileName);
19436        }
19437
19438        return $result;
19439    }
19440
19441    public function getHostedPage() {
19442        $this->layout = '';
19443        $logFileName = isset($this->request->data['logFileName']) ? $this->request->data['logFileName'] : 'debug';
19444
19445        $postData = $this->request->data;
19446        if ($this->request->is('post')) {
19447
19448            // throw exception if there is/are missing parameter(s)
19449            if (
19450                !isset($postData['logFileName']) ||
19451                !isset($postData['apiToken']) ||
19452                !isset($postData['formType']) ||
19453                !isset($postData['successUrl']) ||
19454                !isset($postData['paymentMethodType']) ||
19455                !isset($postData['memKeyError']) ||
19456                !isset($postData['referrer']) ||
19457                (
19458                    empty(trim($postData['apiToken'])) &&
19459                    $postData['apiToken'] !== 0 &&
19460                    $postData['apiToken'] !== '0'
19461                )
19462            ) {
19463                $this->log(__METHOD__ . ' Missing parameters. post data --> ' . json_encode($postData), $logFileName);
19464                throw new BadRequestException("Missing parameter(s).");
19465            }
19466
19467            // set variables
19468            $apiToken = $postData['apiToken'];
19469            $formType = $postData['formType'];
19470            $successUrl = urldecode($postData['successUrl']);
19471            $paymentMethodType = $postData['paymentMethodType'];
19472
19473            // get payment method (debit or credit)
19474            $paymentMethod = explode('_', $paymentMethodType);
19475            $paymentMethod = isset($paymentMethod[0]) ? $paymentMethod[0] : 'debit';
19476
19477            $nominalAmountArr = myTools::getWorldpayNominalAmountList($paymentMethod, myTools::getWPMerchantCode($paymentMethodType));
19478            $memKeyError = $postData['memKeyError'];
19479            $referrer = $postData['referrer'];
19480            $status = 0; // default pending
19481
19482            $userParams = array(
19483                'fields' => array(
19484                    'User.id',
19485                    'User.email',
19486                    'User.nickname',
19487                    'User.card_token',
19488                    'User.charge_flg',
19489                    'User.fail_flg',
19490                    'User.currency_code',
19491                    'User.payment_plan_id',
19492                    'User.price_id',
19493                    'User.double_check_flg',
19494                    'User.status',
19495                    'User.complimentary_code',
19496                    'User.card_company',
19497                    'User.first_charge_date',
19498                    'PaymentPlanPrice.amount'
19499            ),
19500                'apiToken' => $apiToken
19501            );
19502
19503            // throw exception if api token not exist
19504            if (!$userData = $this->User->getWPMobappUserData($userParams)) {
19505                $this->log(__METHOD__ . ' User api token does not exist. User params --> ' . json_encode($userParams), $logFileName);
19506                throw new InternalErrorException("User api token does not exist.");
19507            }
19508
19509            $userId = $userData['User']['id'] ?? null;
19510            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - POST DATA --> ' . json_encode($postData), 'error');
19511
19512            $userCurrencyCode = $userData['User']['currency_code'];
19513            $complimentaryCode = $userData['User']['complimentary_code'];
19514
19515            // NC-9168: override currency if worldpay card auth and JPY currency
19516            $expectedUserCurrency = $this->allowedCurrencies[$this->localizeDir];
19517            if (isset($postData['ncTerminalType']) && $postData['ncTerminalType'] == 1 &&
19518                $formType == Configure::read('payment_credit_authentication') && $userData['User']['currency_code'] != $expectedUserCurrency) {
19519                // Get localized language equivalent currency code
19520                if (
19521                    isset($this->localizeDir) && 
19522                    in_array($this->localizeDir, array_keys($this->allowedCurrencies)) &&
19523                    // do not update currency_code if user account has complimentary code
19524                    empty($complimentaryCode)
19525                ) {
19526                    $userCurrencyCode = ($this->localizeDir == 'zh-cn') ? 'USD' : $this->allowedCurrencies[$this->localizeDir];
19527                    // NC-9629: do not override if JPY
19528                    if ($userCurrencyCode == Configure::read('default.user_currency')) {
19529                        $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - [NC-9629] do not override currency with ' . $userCurrencyCode . ' - ' . json_encode($userData), 'error');
19530                    } else {
19531                        $this->User->validate = array();
19532                        $this->User->read(array('currency_code'), $userData['User']['id']);
19533                        $this->User->set(array('currency_code' => $userCurrencyCode));
19534                        $this->User->save();
19535                        $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - [NC-9168] override currency with ' . $userCurrencyCode . ' - ' . json_encode($userData), 'error');
19536                    }
19537                }
19538            }
19539
19540            // set variables
19541            $paymentPlanPriceAmount = $userData['PaymentPlanPrice']['amount'];
19542            $userData = $userData['User'];
19543            $currencyCode = $userCurrencyCode;
19544            $paymentPlanId = $userData['payment_plan_id'];
19545            $priceId = $userData['price_id'];
19546            $orderCode = myTools::generateOrderCode($userId);
19547            $wpPaymentAmount = $nominalAmountArr[$currencyCode];
19548            $ncPaymentAmount = 0;
19549
19550            switch ($formType) {
19551                case Configure::read('payment_credit_authentication'):
19552                    $tokenReason = 'Payment Credit Registration';
19553                    if (!isset($priceId)) {
19554                        // get payment data
19555                        $paymentData = $this->PaymentPlanPrice->getPaymentData(array(
19556                            'currencyCode' => $currencyCode,
19557                            'paymentPlanId' => Configure::read('payment_plans.free_trial'),
19558                            'logFileName' => $logFileName
19559                        ));
19560
19561                        // throw error exception if does not exist
19562                        if (!$paymentData) {
19563                            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Payment plan does not exist. - payment_credit_authentication', 'error');
19564                            throw new InternalErrorException("Payment plan does not exist.");
19565                        }
19566
19567                        $priceId = $paymentData['priceId'];
19568                    }
19569                    $paymentPlanId = Configure::read('payment_plans.free_trial');
19570
19571                    // Check if membership type is already Premium Plan(Free)
19572                    if (isset($postData['userRegister']) && $postData['userRegister'] == 1 && $this->memcache->get('wp_register_completed_'.$userId)) {
19573                        $this->Auth->login($userData);
19574                        $this->Session->write('redirect-to-notice-to-user', true);
19575                        $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - already_enrolled_free_trial', 'error');
19576                        throw new InternalErrorException('already_enrolled_free_trial');
19577                    }
19578                    break;
19579                case Configure::read('payment_credit_change'):
19580                    if (!isset($priceId) || !isset($paymentPlanId)) {
19581                        $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Price id or payment plan id is/are empty.', 'error');
19582                        throw new InternalErrorException("Price id or payment plan id is/are empty.");
19583                    }
19584
19585                    // add reserve payment amount
19586                    $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userId);
19587
19588                    // add appreciation lesson amount
19589                    $receivablePayment += $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.appreciation'));
19590
19591                    // add live lesson amount
19592                    $receivablePayment += $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.live'));
19593
19594                    // change payment method type to payment, if has receivable payment
19595                    if ($receivablePayment > 0) {
19596                        $paymentMethodType = $paymentMethod . '_payment';
19597                        $wpPaymentAmount = $ncPaymentAmount = $receivablePayment;
19598                    }
19599
19600                    $tokenReason = 'Payment Credit Change';
19601                    break;
19602                case Configure::read('payment_credit_retry'):
19603                    // get payment data
19604                    if (!$paymentData = $this->getRetryPaymentData($userData, $logFileName)) {
19605                        $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Payment plan does not exist. - payment_credit_retry', 'error');
19606                        throw new InternalErrorException("Payment plan does not exist.");
19607                    }
19608
19609                    $wpPaymentAmount = $paymentData['amount'];
19610                    $priceId = $paymentData['priceId'];
19611                    $paymentPlanId = $paymentData['paymentPlanId'];
19612                    
19613                    // NJ-47740 - get monthly reqeust coupon discount
19614                    $coupon = $this->UsersCouponV1->getCouponUseRequest(array(
19615                        'userId' => $userId,
19616                        'kbn' => Configure::read('coupon_kbn.monthly_settlement')
19617                    ));
19618                    
19619                    if (!empty($coupon['amount']) && !empty($coupon['grp_id'])) {
19620                        
19621                        if ($coupon['amount'] >= $wpPaymentAmount) {
19622                            $userData['monthlyDiscount'] = $wpPaymentAmount;
19623                            $wpPaymentAmount = 0;
19624                        } else {
19625                            $wpPaymentAmount -= $userData['monthlyDiscount'] = $coupon['amount'];
19626                        }
19627                        $userData['monthly_grp_id'] = $coupon['grp_id'];
19628                    }
19629
19630                    // add reserve payment amount
19631                    $wpPaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment($userId);
19632
19633                    // add appreciation lesson amount
19634                    $wpPaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.appreciation'));
19635
19636                    // add live lesson amount
19637                    $wpPaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.live'));
19638
19639                    $ncPaymentAmount = $wpPaymentAmount;
19640
19641                    // change payment method type to auth if amount to be paid in is equal to 0
19642                    if ($wpPaymentAmount == 0) {
19643                        $paymentMethodType = $paymentMethod . '_auth';
19644                        $wpPaymentAmount = $nominalAmountArr[$currencyCode];
19645                    }
19646
19647                    $tokenReason = 'Payment Credit Retry';
19648                    break;
19649                case Configure::read('payment_credit_force_charge'):
19650                    // get payment data
19651                    $paymentData = $this->PaymentPlanPrice->getPaymentData(array(
19652                        'currencyCode' => $currencyCode,
19653                        'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
19654                        'logFileName' => $logFileName
19655                    ));
19656
19657                    // throw error exception if does not exist
19658                    if (!$paymentData) {
19659                        $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Payment plan does not exist. - payment_credit_force_charge', 'error');
19660                        throw new InternalErrorException("Payment plan does not exist.");
19661                    }
19662
19663                    $wpPaymentAmount = $paymentData['amount'];
19664                    $priceId = $paymentData['priceId'];
19665                    $paymentPlanId = $paymentData['paymentPlanId'];
19666
19667                    // add reserve payment amount
19668                    $wpPaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment($userId);
19669
19670                    // add live lesson payment amount
19671                    $wpPaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment( $userId, false, Configure::read('appreciation_data.payment_element_type') );
19672                    
19673                    // add live lesson payment amount
19674                    $wpPaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.live'));                    
19675
19676                    $ncPaymentAmount = $wpPaymentAmount;
19677
19678                    // change payment method type to auth if amount is  equal to 0
19679                    if ($wpPaymentAmount == 0) {
19680                        $paymentMethodType = $paymentMethod . '_auth';
19681                        $wpPaymentAmount = $nominalAmountArr[$currencyCode];
19682                    }
19683
19684                    $tokenReason = 'Payment Credit Charge';
19685                    break;
19686            }
19687
19688            $currencyExponents = Configure::read('worldpay.currency_exponents');
19689            $exponent = $currencyExponents[$currencyCode];
19690
19691            // before coupon settlement amount deduction
19692            $beforeCouponSettlementAmount = $ncPaymentAmount;
19693
19694            // NJ-32737
19695            $couponData = $this->Session->read('apply_coupon_usage_data');
19696
19697            $membershipStatusIndex = UserTable::getStudentMembershipStatus($userId);
19698            if (in_array($membershipStatusIndex, Configure::read('allow_coupon.settlement')) &&
19699                isset($formType) &&
19700                in_array($formType, Configure::read('allow_coupon.settlement_form_type'))
19701            ) {
19702                // confiscate the coupon pending request when student is re-enrolled
19703                $res_confiscate = $this->UsersCouponV1->confiscateAllCoupon(array(
19704                    'userId' => $userId,
19705                    'action_type' => 1 // only the pending request will be confiscated
19706                ));
19707                
19708                if (!$res_confiscate) {
19709                    $this->log(__METHOD__ . ' Failed to confiscate coupon pending request. User id --> ' . $userId, $logFileName);
19710                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to confiscate coupon pending request. User id --> ' . $userId, 'error');
19711                }
19712
19713                if (isset($couponData['useCouponAmount']) && $couponData['useCouponAmount'] > 0) {
19714                    if ($wpPaymentAmount >= $couponData['useCouponAmount']) {
19715                        $wpPaymentAmount -= $couponData['useCouponAmount'];
19716                        $ncPaymentAmount -= $couponData['useCouponAmount'];
19717                    } else {
19718                        $wpPaymentAmount = 0;
19719                        $ncPaymentAmount = 0;
19720                    }
19721
19722                    // change niminal amount if amount is  equal to 0
19723                    if ($wpPaymentAmount == 0) {
19724                        $wpPaymentAmount = $nominalAmountArr[$currencyCode];
19725                    }
19726
19727                    $couponUseSettlement = $couponData;
19728                }
19729            }
19730            // NJ-32737-end
19731
19732            // get total amount with checking currency exponent
19733            $totalAmountArr = myTools::wpGetAmount($exponent, $wpPaymentAmount);
19734            $wpPaymentAmount = $totalAmountArr['wpAmount'];
19735
19736            $merchantCode = myTools::getWPMerchantCode($paymentMethodType);
19737
19738            $paymentParams = array(
19739                'currencyCode' => $currencyCode,
19740                'formType' => $formType,
19741                'logFileName' => $logFileName,
19742                'remoteAddress' => $_SERVER["REMOTE_ADDR"],
19743                'cardToken' => isset($userData['card_token']) ? $userData['card_token'] : null,
19744                'newCard' => true,
19745                'merchantCode' => $merchantCode,
19746                'wpPaymentAmount' => $wpPaymentAmount,
19747                'paymentAmount' => $ncPaymentAmount,
19748                'priceId' => $priceId,
19749                'paymentPlanId' => $paymentPlanId,
19750                'paymentType' => Configure::read('payment_types.payment_plan')
19751            );
19752
19753            if (!empty($couponUseSettlement)) {
19754                $paymentParams['couponUseSettlement'] = $couponUseSettlement;
19755            }
19756            
19757            if (!empty($coupon) && isset($formType) && $formType == Configure::read('payment_credit_retry') && !empty($userData['monthlyDiscount']) && !empty($userData['monthly_grp_id'])) {
19758                $paymentParams['discounted_amount'] = $userData['monthlyDiscount'];
19759                $paymentParams['monthlyDiscount'] = $userData['monthlyDiscount'];
19760                $paymentParams['monthly_grp_id'] = $userData['monthly_grp_id'];
19761            }
19762
19763            if (isset($postData['userRegister']) && $postData['userRegister']) {
19764                $paymentParams['userRegister'] = true;
19765            }
19766
19767            // NJ-42971: free trial checker
19768            $notFreeTrial = true;
19769
19770            if ($formType != Configure::read('payment_credit_change')) {
19771                $membershipTypes = UserTable::getEngMembershipTypeData();
19772                $statusAfter = $membershipTypes[1]; // premium plan paid
19773
19774                /* -- get before status -- */
19775                if ($this->memcache->get('com_plan_user_' . $userId) && $userData && $userData['payment_plan_id'] == Configure::read('payment_plans.complimentary_plan')) {
19776                    $statusBefore = $membershipTypes[15]; // complimentary code
19777                    $paymentParams['bonusCoinFlg'] = 1;
19778                    $paymentParams['updateFirstChargeDate'] = true;
19779                } elseif ($userData['charge_flg'] == 0) {
19780                    // failed settlement
19781                    if ($userData['fail_flg'] == 1) {
19782                        $statusBefore = $membershipTypes[5];
19783                    // trial again
19784                    } elseif ($userData['fail_flg'] == 0 && $userData['double_check_flg'] == 1) {
19785                        $statusBefore = $membershipTypes[13];
19786                        $notFreeTrial = false;
19787                    // unsubscribed
19788                    } elseif ($userData['fail_flg'] == 0 && $userData['double_check_flg'] == 2) {
19789                        $statusBefore = $membershipTypes[12];
19790                    // temporary
19791                    } elseif ($userData['status'] == 0) {
19792                        $statusBefore = $membershipTypes[6];
19793                        $statusAfter = $membershipTypes[2]; // premium plan free
19794                    } else {
19795                        $statusBefore = null;
19796                    }
19797                }
19798
19799                if (isset($statusBefore)) {
19800                    $user = new UserTable($userData);
19801                    $membershipTypeIndex = $user->getMembershipTypeIndex();
19802
19803                    if ($membershipTypeIndex == 13) {
19804                        $statusBefore = $membershipTypes[13];
19805                        $paymentParams['userRegister'] = true;
19806                        $notFreeTrial = false;
19807                        $statusAfter = $membershipTypes[2];
19808                    }
19809
19810                    // get platform use
19811                    $platform = myTools::mobappDetectPlatform();
19812                    $paymentParams['platform'] = $platform == Configure::read('platform.splp') ? Configure::read('platform.pclp') : $platform;
19813                    $paymentParams['statusBefore'] = $statusBefore;
19814                    $paymentParams['statusAfter'] = $statusAfter;
19815
19816                    $user = new UserTable($userData);
19817                    $membershipTypeIndex = $user->getMembershipTypeIndex();
19818
19819                    if ($membershipTypeIndex == 13) {
19820                        $paymentParams['userRegister'] = true;
19821                    }
19822                }
19823            }
19824
19825            $ptParams = array(
19826                'user_id' => $userId,
19827                'payment_hash' => $orderCode,
19828                'status' => $status,
19829                'payment_params' => json_encode($paymentParams),
19830                'course_id' => Configure::read("credit.course_id")
19831            );
19832
19833            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Before WP Payment Transaction Creation - Params --> ' . json_encode($ptParams), 'error');
19834
19835            // throw exception if failed to save payment transaction
19836            if (!$pt = $this->PaymentTransaction->setWPPaymentTransaction($ptParams)) {
19837                $this->log(__METHOD__ .' Failed to save payment transaction. update data --> ' . json_encode($ptParams), $logFileName);
19838                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to save payment transaction. update data --> ' . json_encode($ptParams), 'error');
19839                throw new InternalErrorException("Failed to save payment transaction.");
19840            }
19841
19842            $this->Session->write('wp_coupon_settlement_payment', [
19843                'payment_hash' => $pt['payment_hash'],
19844                'payment_amount' => $beforeCouponSettlementAmount // set before coupon settlement amount
19845            ]);
19846
19847            $wpData = array(
19848                'merchantCode' => $merchantCode,
19849                'orderCode' => $orderCode,
19850                'installationId' => Configure::read('worldpay.default_installation_id'),
19851                'currencyCode' => $currencyCode,
19852                'exponent' => $exponent,
19853                'amount' => $wpPaymentAmount,
19854                'email' => $userData['email'],
19855                'authenticatedShopperId' => $userId,
19856                'tokenEventReference' => $orderCode,
19857                'tokenReason' => $tokenReason,
19858                'xmlName' => 'hosted_reference_url',
19859                'paymentMethod' => $paymentMethod
19860            );
19861
19862            $this->log('getHostedReferenceUrl -- ' . json_encode($wpData), $logFileName);
19863            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Before getHostedReferenceUrl --> ' . json_encode($wpData), 'error');
19864
19865            $result = wpPaymentService::getHostedReferenceUrl($wpData);
19866            $hostedUrl = null;
19867            if (isset($result['paymentService']) && is_array($result['paymentService'])) {
19868                if (isset($result['paymentService']['reply']) && is_array($result['paymentService']['reply'])) {
19869                    if (isset($result['paymentService']['reply']['orderStatus']) && is_array($result['paymentService']['reply']['orderStatus'])) {
19870                        if (isset($result['paymentService']['reply']['orderStatus']['reference']) && is_array($result['paymentService']['reply']['orderStatus']['reference'])) {
19871                            if (isset($result['paymentService']['reply']['orderStatus']['reference']['@'])) {
19872                                $hostedUrl = $result['paymentService']['reply']['orderStatus']['reference']['@'];
19873                            }
19874                        }
19875                    }
19876                }
19877            }
19878
19879            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - After getHostedReferenceUrl --> ' . json_encode($result), 'error');
19880
19881            // if hostedUrl is null, set payment transaction status to 2
19882            if (!isset($hostedUrl)) {
19883                $status = 2; // error
19884            }
19885
19886            $updateData = array(
19887                'id' => $pt['id'],
19888                'fields' => array(
19889                    'response_text' => array('hostedReferenceUrl_response' => $result),
19890                    'status' => $status
19891                ),
19892                'logFileName' => $logFileName
19893            );
19894
19895            // redirect to retry page if failed to update payment transaction
19896            if (!$this->updatePaymentTransaction($updateData)) {
19897                $this->log(__METHOD__ .' Failed to update payment transaction. update data --> ' . json_encode($updateData), $logFileName);
19898                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to update payment transaction. update data --> ' . json_encode($updateData), 'error');
19899                throw new InternalErrorException("Failed to update payment transaction.");
19900            }
19901
19902            // throw exception if unable to generate hosted URL
19903            if (!isset($hostedUrl)) {
19904                $this->autoRender = $this->layout = false;
19905                myTools::parseAndSetWPErrorResponse(array(
19906                    'apiToken' => $apiToken,
19907                    'wpResponse' => $result,
19908                    'memKey' => $memKeyError
19909                ));
19910                $this->log(__METHOD__ .' Unable to generate hosted URL. get hosted url response --> ' . json_encode($ptParams), $logFileName);
19911                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Unable to generate hosted URL. get hosted url response  --> ' . json_encode($ptParams), 'error');
19912                throw new NotFoundException("Unable to generate hosted URL.");
19913            }
19914
19915            if ($formType == Configure::read('payment_credit_authentication')) {
19916                //NJ-13482
19917                $this->Session->write('reenroll_native_option', true);
19918            }
19919
19920            //    NC-7644 Add code reward for re-enroolling with the campaign code
19921            if($formType == Configure::read('payment_credit_force_charge')){
19922                $this->addCoinRewardForReenroll($userData);
19923            }
19924            
19925            // Teacher Perks : Student re-enroll
19926            if ( $formType == Configure::read('payment_credit_force_charge')) {
19927                ClassRegistry::init('TeacherPerksAccount')->reEnroll(['user_id' => $userData['id']]);
19928            }
19929
19930            $this->set('logFileName', $logFileName);
19931            $this->set('apiToken', $apiToken);
19932            $this->set('successUrl', $successUrl);
19933            $this->set('referrer', $referrer);
19934            $this->set('hostedUrl', $hostedUrl);
19935            $this->set('ncTerminalType', isset($postData['ncTerminalType']) ? $postData['ncTerminalType'] : 0);
19936
19937        // throw exception if method used is not POST
19938        } else {
19939            $this->log(__METHOD__ . ' Method used is not POST --> ' . json_encode($postData), 'debug');
19940            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Method used is not POST --> ' . json_encode($postData), 'error');
19941            throw new MethodNotAllowedException("Method used is not POST.");
19942        }
19943
19944        $this->render('/Elements/mobapp/wp_get_hosted_page');
19945    }
19946
19947    /**
19948     * NC-4770: Delete user previous card token use in wp
19949     * @param array $params
19950     * @return array $res
19951     */
19952    public function deleteUserToken($params = array()) {
19953        $result = wpPaymentService::deleteUserToken($params['deleteTokenParams']);
19954        $deleteToken = isset($result['paymentService']['reply']['ok']['deleteTokenReceived']) ? true : false;
19955
19956        // log if failed to delete token in wp
19957        if (!$deleteToken) {
19958            $this->log(__METHOD__ . ' Failed to delete user wp card token. params --> ' . json_encode($params['deleteTokenParams']) . ", error(s) --> " . $deleteTokenResultJson .' | kickback data --> ' . $params['dataJson'], $params['logFileName']);
19959        }
19960
19961        return $result;
19962    }
19963
19964    /**
19965     * NC-4770: worldpay memcache payment transaction and etc.
19966     * @param array $params
19967     */
19968    private function memcacheWPPayment($params = array()) {
19969        // set to memcache
19970        $this->memcache->set(array(
19971            'key' => $params['memKey'],
19972            'value' => array(
19973                'withPaymentTransaction' => true,
19974                'hostedUrl' => isset($params['mc']['hostedUrl']) ? $params['mc']['hostedUrl'] : (isset($params['hostedUrl']) ? $params['hostedUrl'] : null),
19975                'orderCode' => isset($params['mc']['orderCode']) ? $params['mc']['orderCode'] : (isset($params['orderCode']) ? $params['orderCode'] : null),
19976                'ptId' => isset($params['mc']['ptId']) ? $params['mc']['ptId'] : (isset($params['ptId']) ? $params['ptId'] : null),
19977                'isUseNewCard' => isset($params['isUseNewCard']) ? $params['isUseNewCard'] : (isset($params['mc']['isUseNewCard']) ? $params['mc']['isUseNewCard'] : 0)
19978            ),
19979            'expire' => 3600 // 1 hr
19980        ));
19981    }
19982
19983    private function memcacheCardType($params = array()) {
19984        // memcache card type value
19985        $this->memcache->set(array(
19986            'key' => $params['key'],
19987            'value' => $params['value'],
19988            'expire' => 3600 // 1 hr
19989        ));
19990    }
19991
19992    /**
19993     * NC-4770: worldpay process payment transaction.
19994     * @param array $params
19995     * @return string 'ok' or exception
19996     */
19997    public function processWPPayment($params) {
19998        $logFileName = isset($params['logFileName']) ? $params['logFileName'] : 'debug';
19999        $orderCode = isset($params['data']['OrderCode']) ? $params['data']['OrderCode'] : '';
20000        $paymentStatusName = isset($params['data']['PaymentStatus']) ? $params['data']['PaymentStatus'] : '';
20001        $userId = isset($params['ptData']['user_id']) ? $params['ptData']['user_id'] : null;
20002
20003        if (
20004            !isset($params['data']) || !isset($params['ptData']) ||
20005            !isset($params['amount']) || !isset($params['userData'])
20006        ) {
20007            $msg = ' Missing parameters.';
20008            $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
20009            $this->log(__METHOD__ . ' ' . $msg . ' Parameters --> ' . json_encode($params), $logFileName);
20010            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' Parameters --> ' . json_encode($params), 'error');
20011            echo "[OK]"; exit;
20012        }
20013
20014        $membershipStatusIndex = UserTable::getStudentMembershipStatus($userId);
20015
20016        // set variables
20017        $data = $params['data'];
20018        $dataJson = json_encode($data);
20019        $dateNow = date("Y-m-d H:i:s");
20020        $paymentTransactionData = $params['ptData'];
20021        $cardCompany = Configure::read('card_company.worldpay');
20022        $amount = $params['amount'];
20023        $paymentStatus = 1;
20024        $typeId = 1;
20025        $platform = Configure::read('platform.pclp');
20026        $receivablePayment = $params['receivablePayment'];
20027        $appreciationReceivable = $params['appreciationReceivable'];
20028        $liveLessonReceivable = $params['liveLessonReceivable'];
20029        $ptPaymentParams = json_decode($paymentTransactionData['payment_params'], true);
20030        $currencyCode = isset($ptPaymentParams['currencyCode']) ? $ptPaymentParams['currencyCode'] : null;
20031        $ptResponseText = array('wp_kickback' => $data);
20032        $ptPassword = $paymentTransactionData['password'];
20033        $formType = $ptPaymentParams['formType'];
20034        $cronDateRun = $params['cronDateRun'];
20035        $userData = $params['userData'];
20036        $transactionIdentifier = $params['transactionIdentifier'];
20037        $merchantCode = isset($ptPaymentParams['merchantCode']) ? $ptPaymentParams['merchantCode'] : Configure::read('worldpay.merchant_code_usd');
20038        $paymentPlanId = isset($ptPaymentParams['paymentPlanId']) ? $ptPaymentParams['paymentPlanId'] : null;
20039        $paymentType = isset($ptPaymentParams['paymentType']) ? $ptPaymentParams['paymentType'] : null;
20040        $priceId = isset($ptPaymentParams['priceId']) ? $ptPaymentParams['priceId'] : null;
20041        $familyId = isset($ptPaymentParams['familyId']) ? $ptPaymentParams['familyId'] : null;
20042        $parentId = isset($userData['User']['parent_id']) ? $userData['User']['parent_id'] : $ptPaymentParams['parentId'];
20043        $discounted_amount = isset($ptPaymentParams['discounted_amount']) ? $ptPaymentParams['discounted_amount'] : 0;
20044
20045        // if using coupon during force settlement
20046        if (
20047            !empty($ptPaymentParams['couponUseSettlement']) && 
20048            !empty($ptPaymentParams['couponUseSettlement']['useCouponAmount']) && 
20049            in_array($formType, Configure::read('allow_coupon.settlement_form_type'))
20050        ) {
20051            $discounted_amount += $ptPaymentParams['couponUseSettlement']['useCouponAmount'];
20052        }
20053
20054        $userId = $familyId ? $familyId : $userId;
20055        $appreciationFlg = 0;
20056        $tipAmount = null;
20057
20058
20059        $currency_before = $currencyCode;
20060        $plan_before = $paymentPlanId;
20061        $membershipStatusIndex = isset($ptPaymentParams['membershipStatusIndex']) && $ptPaymentParams['membershipStatusIndex'] ? $ptPaymentParams['membershipStatusIndex'] : $membershipStatusIndex;
20062        $uModel = $this->User;
20063
20064        if (in_array($formType, array(Configure::read('payment_credit_retry'), Configure::read('payment_credit_authentication')))) {
20065            $typeId = 2;
20066        } 
20067
20068        if (isset($amount) && $amount < 0) {
20069            $typeId = 0;
20070        }
20071
20072        $userData = $userData['User'];
20073        $pModel = $this->Payment;
20074
20075        // check if family plan
20076        if (
20077            $familyId && 
20078            $parentId && 
20079            (
20080                in_array($formType, array(Configure::read('payment_credit_coin_purchase'), Configure::read('payment_credit_textbook_purchase'))) 
20081                ||
20082                (
20083                    isset($ptPaymentParams['nativeOptionJoin']) && 
20084                    $ptPaymentParams['nativeOptionJoin'] && 
20085                    $ptPaymentParams['formType'] == Configure::read('payment_native_option_join')
20086                )
20087                ||
20088                (
20089                    isset($ptPaymentParams['callanOptionJoin']) && 
20090                    $ptPaymentParams['callanOptionJoin'] && 
20091                    $ptPaymentParams['formType'] == Configure::read('payment_callan_option_join')
20092                )
20093            )
20094        ) {
20095            // change reference id to parent id
20096            $referenceId = $parentId;
20097        } else {
20098            $referenceId = $userId;
20099        }
20100
20101        // set variables
20102        $paymentData = array(
20103            'user_id' => $userId,
20104            'type_id' => $typeId,
20105            'reference_id' => $referenceId,
20106            'payment_transaction_password' => $ptPassword,
20107            'status' => $paymentStatus,
20108            'form_type' => $formType,
20109            'ordd' => $orderCode,
20110            'amount' => $amount,
20111            'param1' => $dataJson,
20112            'card_company' => $cardCompany,
20113            'transaction_code' => $orderCode,
20114            'currency_code' => $currencyCode,
20115            'payment_id' => $paymentPlanId,
20116            'price_id' => $priceId,
20117            'payment_type' => $paymentType,
20118        );
20119        
20120        $discountType = 'monthly';
20121        if ($formType == Configure::read('payment_native_option_join')) {
20122            $discountType = 'native';
20123        } else if ($formType == Configure::read('payment_callan_option_join')) {
20124            $discountType = 'callan';
20125        } else if ($formType == Configure::read('payment_credit_coin_purchase')) {
20126            $discountType = 'coin';
20127        }
20128        
20129        // NJ-47740
20130        $getCouponDiscounDetail = PaymentTable::getCouponDiscountRequestDetail($ptPaymentParams, $discountType);
20131        $paymentData['discounted_amount'] = !empty($getCouponDiscounDetail['discounted_amount']) ? $getCouponDiscounDetail['discounted_amount'] : 0;
20132        $paymentData['coupon_request_id'] = !empty($getCouponDiscounDetail['coupon_request_id']) ? $getCouponDiscounDetail['coupon_request_id'] : null;
20133        
20134        $forceSettlementWithCoupon  = false;
20135        // if using coupon during force settlement
20136        if (
20137            !empty($ptPaymentParams['couponUseSettlement']) && 
20138            !empty($ptPaymentParams['couponUseSettlement']['useCouponAmount']) && 
20139            in_array($formType, Configure::read('allow_coupon.settlement_form_type'))
20140        ) {
20141            // apply coupon use discount
20142            $couponData = $ptPaymentParams['couponUseSettlement'];
20143            $couponData['nextChargeDate'] = date('Y-m-d');
20144            $couponData['request_result'] = true;
20145
20146            $result_coupon_use = $this->UsersCouponV1->performCouponUse($couponData);
20147            $result_coupon_use = !empty($result_coupon_use) ? json_decode($result_coupon_use,true) : array();
20148
20149            if (empty($result_coupon_use)) {
20150                $this->log(__METHOD__ . ' Failed to used coupons.' . json_encode($couponData), $logFileName);
20151                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to used coupons.' . json_encode($couponData), 'error');
20152                $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to used coupons.', $couponData, array_merge($_POST, $_SERVER));
20153                return false;
20154            }
20155            
20156            $paymentData['discounted_amount'] = $ptPaymentParams['couponUseSettlement']['useCouponAmount'];
20157            $paymentData['coupon_request_id'] = isset($result_coupon_use['cgrp_id']) ? $result_coupon_use['cgrp_id'] : null;
20158            
20159            $forceSettlementWithCoupon = true;
20160        }
20161        // NJ-47740 - end
20162        
20163        $discountOption = isset($ptPaymentParams['discountOption']) ? $ptPaymentParams['discountOption'] : [];
20164    
20165        if (!empty($discountOption)) {
20166            $paymentData['discount_option_price_id'] = $discountOption['discount_option_price_id'];
20167        }
20168            
20169        //- check payment receivable with zero amount
20170        if (
20171            $formType == Configure::read('payment_credit_receivable') &&
20172            $amount <= 0
20173        ) {
20174            //- skip saving
20175        } else {
20176            // create new payment
20177            $pModel->clear();
20178            $pModel->create();
20179            $pModel->validate = array();
20180            $pModel->set($paymentData);
20181
20182            // return if not save
20183            if (!$paymentSave = $pModel->save()) {
20184                $msg = 'Saving payment failed.';
20185                $this->log(__METHOD__ . ' ' . $msg . ' Payment data --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, $logFileName);
20186                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' Payment data --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, 'error');
20187                $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
20188                
20189                // if payment failed and has coupon grp id and its direct payment -> unconfirm coupon
20190                if (
20191                    isset($paymentData['coupon_request_id']) && $paymentData['coupon_request_id'] &&
20192                    (
20193                        // the native or callan purchase with coupon use already has checker while processing the payment
20194                        // to ensure that payment errors are caught, place it here as well to make sure that the coupon is unconfirmed in case the page is refreshed while processing
20195                        in_array(
20196                            $formType, array(
20197                                Configure::read('payment_native_option_join'),
20198                                Configure::read('payment_callan_option_join'),
20199                                Configure::read('payment_credit_coin_purchase')
20200                            )
20201                        ) ||
20202                        // force settlement with coupon
20203                        $forceSettlementWithCoupon
20204                    )
20205                ) {
20206                    $couponKbn = Configure::read('coupon_kbn.coin_purchase'); // default
20207                    if ($formType == Configure::read('payment_native_option_join')) {
20208                        $couponKbn = Configure::read('coupon_kbn.native_option');
20209                    } else if ($formType == Configure::read('payment_callan_option_join')) {
20210                        $couponKbn = Configure::read('coupon_kbn.callan_option');
20211                    } else if ($forceSettlementWithCoupon) {
20212                        $couponKbn = Configure::read('coupon_kbn.monthly_settlement');
20213                    }
20214                    
20215                    $res_unconfirm = $this->UsersCouponV1->performCouponUnconfirm(array(
20216                        'grpId' => $paymentData['coupon_request_id'],
20217                        'userId' => $userId,
20218                        'kbn' => $couponKbn
20219                    ));
20220
20221                    if (empty($res_unconfirm)) {
20222                        $this->log(__METHOD__ . ' failed to perform coupon unconfirm.', $logFileName);
20223                        $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - failed to perform coupon unconfirm.', 'error');
20224                    }
20225                }
20226                
20227                throw new InternalErrorException($msg);
20228            }
20229            //update/add user`s settlement amount
20230            $this->User->updateUserPayments($paymentData);
20231            $paymentId = $paymentSave['Payment']['id'];
20232
20233            // set payment_id
20234            $paymentSaveID = $this->Payment->id;
20235            
20236            // NJ-47740
20237            if (!empty($paymentData['coupon_request_id']) && $paymentData['discounted_amount'] > 0) {
20238                // confirm coupon use request for discount
20239                $requestCouponConfirmData = array(
20240                    'grpId' => $paymentData['coupon_request_id'],
20241                    'paymentId' => $paymentSaveID
20242                );
20243                $result_confirm = $this->UsersCouponV1->performCouponConfirm($requestCouponConfirmData);
20244                
20245                if (!$result_confirm) {
20246                    $msg = 'Failed to confirm coupon use request.';
20247                    $this->log(__METHOD__ . ' Failed to confirm coupon use request. ' . json_encode($requestCouponConfirmData) . ' -- ' . $dataJson, $logFileName);
20248                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to confirm coupon use request. ' . json_encode($requestCouponConfirmData) . ' -- ' . $dataJson, 'error');
20249                    $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
20250                    throw new InternalErrorException($msg);
20251                }
20252            }
20253            // NJ-47740 end
20254            
20255            // NJ-35237
20256            if (!empty($ptPaymentParams['rewardedPoints'])) {
20257                $rewaredPointParams['ContinuationRewardPoint'] = $ptPaymentParams['rewardedPoints'];
20258                // save reward point
20259                if (!$this->ContinuationRewardPoint->saveRewardPoint($rewaredPointParams)) {
20260                    $this->log(__METHOD__ . ' Failed to save reward point. --> ' . json_encode($ptPaymentParams['rewardedPoints']), $logFileName);
20261                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to save reward point. --> ' . json_encode($ptPaymentParams['rewardedPoints']), 'error');
20262                }
20263            }
20264            // NJ-35237 end
20265            
20266            // update payment details
20267            $updatePaymentDetailParams = array(
20268                'currencyCode' => $paymentData['currency_code'],
20269                'formType' => $paymentData['form_type'],
20270                'paymentType' => $paymentData['payment_type'],
20271                'amount' => $paymentData['amount'],
20272                'discounted_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0,
20273                'familyId' => $familyId,
20274                'cronDateRun' => $cronDateRun,
20275                'priceId' => $paymentData['price_id'],
20276                'paymentPlanId' => $paymentData['payment_id'],
20277                'user_id' => $paymentData['user_id'],
20278                'coupon_use_request_id' => isset($paymentData['coupon_request_id']) ? $paymentData['coupon_request_id'] : null,
20279                'coupon_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0
20280            );
20281            
20282            if (!empty($discountOption)) {
20283                $updatePaymentDetailParams['discount_option_price_id'] = $discountOption['discount_option_price_id'];
20284                $updatePaymentDetailParams['discount_option_amount'] = $discountOption['amount'];
20285            }
20286
20287            $updatePaymentDetail = array(
20288                'id' => $paymentTransactionData['id'],
20289                'fields' => array(
20290                    'payment_details' => $updatePaymentDetailParams
20291                )
20292            );
20293
20294            if (!$this->PaymentTransaction->updateWPPaymentTransaction($updatePaymentDetail)) {
20295                $this->log(__METHOD__ . ' Failed to update payment details. ' . json_encode($updatePaymentDetail), $logFileName);
20296                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to update payment details - on create new payment ' . json_encode($updatePaymentDetail), 'error');
20297            }
20298        }
20299
20300        // if payment was saved, and form type belongs to textbook purchase,
20301        // update textbook_sales table, insert payment_id
20302        if ($formType == Configure::read('payment_credit_textbook_purchase')) {
20303            // set textbook sales info
20304            $textbookSales = $this->TextbookSale->find('first', array(
20305                'conditions' => array(
20306                    'TextbookSale.sales_code' => $ptPassword
20307                ),
20308                'recursive' => -1
20309            ));
20310            
20311            // if has textbook sales, update payment_id
20312            if ($textbookSales) {
20313                $this->TextbookSale->clear();
20314                if (!$this->TextbookSale->read(null, $textbookSales['TextbookSale']['id'])) {
20315                    $msg = 'Textbook sales id does not exist.';
20316                    $this->log(__METHOD__ . ' ' . $msg . json_encode($textbookSales), $logFileName);
20317                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . json_encode($textbookSales), 'error');
20318                    $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
20319                    echo "[OK]"; exit;
20320                }
20321                $this->TextbookSale->set('payment_id', $paymentId);
20322                $this->TextbookSale->set('payment_status', 1);
20323                if (!$this->TextbookSale->save()) {
20324                    $msg = 'Failed to update textbook sales payment status to 1.';
20325                    $this->log(__METHOD__ . ' ' . $msg . json_encode($textbookSales), $logFileName);
20326                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . json_encode($textbookSales), 'error');
20327                    $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
20328                    throw new InternalErrorException($msg);
20329                }
20330            }
20331        }
20332
20333        // check if form type is not equals to textbook purchase or receivable
20334        if (
20335            $formType != Configure::read('payment_credit_coin_purchase') &&
20336            $formType != Configure::read('payment_credit_textbook_purchase') &&
20337            $formType != Configure::read('payment_credit_receivable') &&
20338            $formType != Configure::read('payment_credit_appreciation_receivable') &&
20339            $formType != Configure::read('payment_native_option_monthly_payment') &&
20340            $formType != Configure::read('payment_native_option_join') &&
20341            $formType != Configure::read('payment_callan_option_monthly_payment') &&
20342            $formType != Configure::read('payment_callan_option_join')
20343        ) {
20344            // set user array to be save
20345            $saveUserArr = array(
20346                'modified' => $dateNow,
20347                'fail_flg' => 0,
20348                'charge_flg' => 1,
20349                'counseling_attended_flg' => 0,
20350                'card_company' => $cardCompany,
20351                'hash16' => $userId,
20352                'last_charge_date' => $dateNow,
20353                'wp_transaction_identifier' => $transactionIdentifier,
20354                'payment_plan_id' => $paymentPlanId,
20355                'price_id' => $priceId
20356            );
20357            //NJ-7874 if appreciation flag and amount is set
20358            if (isset($ptPaymentParams['family_data']['applyPlan']['tip_max_amount']) && $ptPaymentParams['family_data']['applyPlan']['tip_max_amount']) {
20359                $tipAmount = $ptPaymentParams['family_data']['applyPlan']['tip_max_amount'];
20360            }
20361
20362            if (isset($ptPaymentParams['family_data']['applyPlan']['allow_appreciation_flg']) && $ptPaymentParams['family_data']['applyPlan']['allow_appreciation_flg'] && $tipAmount) {
20363                $appreciationFlg = 1;
20364            }
20365            // NJ-1562 - appreciation on
20366            if( $paymentPlanId && in_array( $paymentPlanId, Configure::read('appreciation.payment_plan_id') ) ) {
20367                $saveUserArr['allow_appreciation_flg'] = 1; // on
20368
20369                //NJ-7548 : 
20370                if (
20371                    !in_array($paymentPlanId,Configure::read('appreciation.can_coin_purchase_check')) &&
20372                    (
20373                        $formType == Configure::read('payment_credit_authentication') ||
20374                        $formType == Configure::read('payment_credit_change') || 
20375                        $formType == Configure::read('payment_credit_force_charge') || 
20376                        $formType == Configure::read('payment_credit_retry')
20377                    )
20378                ) {
20379                    //fetch the age
20380                    $userAge = UserTable::getStudentAge($userData['birthday']);
20381                    $userAge = $userAge ? (int) $userAge : null;
20382                    $showAppreciationFlg = 0;
20383
20384                    //change the show appreciation flg if no birthday set or 18 and above            
20385                    if (!$userAge || $userAge >= 18) {
20386                        $saveUserArr['show_appreciation_flg'] = 1; // on
20387                    }
20388                }
20389                //NJ-7874 set appreciation settings for Family Plan
20390                if (in_array($paymentPlanId, Configure::read('appreciation.can_coin_purchase_check')) ) {
20391                    $saveUserArr['allow_appreciation_flg'] = $appreciationFlg;
20392                    $saveUserArr['show_appreciation_flg'] = $appreciationFlg;
20393                    $saveUserArr['tip_max_amount'] = $tipAmount;
20394                }
20395            }
20396
20397            // check payment if credit authentication
20398            if (in_array($formType, array(Configure::read('payment_credit_authentication'), Configure::read('payment_credit_family_free'))) 
20399                || isset($ptPaymentParams['updateFirstChargeDate'])
20400            ) {
20401                $saveUserArr['first_charge_date'] = $dateNow;
20402                // $saveUserArr['platform'] = $platform;
20403            }
20404
20405            // if bonus coin flg is set
20406            if (isset($ptPaymentParams['bonusCoinFlg'])) {
20407                $saveUserArr['bonus_coin_flg'] = $ptPaymentParams['bonusCoinFlg'];
20408            }
20409
20410            // get time today plus 1 hour
20411            $nextChargeTime = (time() + 3600) - strtotime('TODAY');
20412
20413            // check if subscription payment
20414            if (
20415                $formType == Configure::read('payment_credit_force_charge') ||
20416                $formType == Configure::read('payment_credit_retry') ||
20417                $formType == Configure::read('payment_credit_monthly_payment') ||
20418                $formType == Configure::read('payment_credit_family_monthly_payment') ||
20419                $formType == Configure::read('payment_credit_family_free')
20420            ) {
20421
20422                if ($formType == Configure::read('payment_credit_monthly_payment')) {
20423                    $nextChargeTime = strtotime($userData['next_charge_date']) - strtotime('TODAY');
20424                }
20425
20426                // set minutes and seconds to 00:00 always
20427                $nextChargeDate = date('Y-m-d H:00:00', strtotime('+' . $nextChargeTime . ' second ' . $this->User->getNextChargeDate()));
20428                $saveUserArr['next_charge_date'] = $nextChargeDate;
20429                $saveUserArr['double_check_flg'] = 1;
20430                $saveUserArr['expired_card_flg'] = 0;
20431
20432                // give points to user join the campaign who retry payment
20433                if ($formType == Configure::read('payment_credit_retry')) {
20434                    $this->ContinuationCampaign->givePointsRetrySuccess(array(
20435                        'user_ids' => array($userId)
20436                    ));
20437                }
20438
20439                if ($formType == Configure::read('payment_credit_family_free')) {
20440                    $nextChargeDate = date('Y-m-d H:00:00', strtotime('+' . $nextChargeTime . ' second ' . $this->User->getFirstNextChargeDate()));
20441                    $saveUserArr['next_charge_date'] = $nextChargeDate;
20442                }
20443
20444                // give points if user join campaign and success payment
20445                if ($formType == Configure::read('payment_credit_monthly_payment')) {
20446                    $this->ContinuationCampaign->givePoints(array(
20447                        'user_id' => $userId
20448                    ));
20449                }
20450
20451                // Worldpay: sync all add child behaviour -> set next charge date to current hour
20452                if ($formType == Configure::read('payment_credit_family_monthly_payment')) {
20453                    $nextChargeDate = date('Y-m-d H:00:00', strtotime('+' . (time() - strtotime('TODAY')) . ' second ' . $this->User->getNextChargeDate()));
20454                    $saveUserArr['next_charge_date'] = $nextChargeDate;
20455                }
20456
20457
20458                # give coins if temporary/new user is changed/added to family plan
20459                if ($formType == Configure::read('payment_credit_family_free') && $userData['status'] == 0) {
20460                    // NJ-4746: defult bonus point
20461                    $defaultBC = ClassRegistry::init("DefaultCoinRegistration")->defaultCoins();
20462                    $bonusPoints = (($defaultBC > 0) ? $defaultBC : Configure::read("credit.bonus_coin_authentication"));
20463
20464                    // camapaign master triiger 1
20465                    $campaignMaster = ClassRegistry::init('CampaignMaster')->bonusTrigger(['userId' => $userData['id'], 'triggerNo' => 1]);
20466                    if (!$campaignMaster['bonusCoins'] && !$campaignMaster['bonusCoupons']) {
20467                        # add to the user's existing coin
20468                        $pointParams = array(
20469                            'userId' => $userData['id'],
20470                            'point' => $bonusPoints,
20471                            'kbn' => Configure::read("point_history.bonus"),
20472                            'kbnType' => 1, // add coin
20473                            'coinType' => 2, // service coin
20474                            'coinFailMessage' => Configure::read('coin.failed.campaign')
20475                        );
20476                        if (!$this->UsersPoint->performPointTransaction($pointParams)) {
20477                            $msg = 'Failed add point to user.';
20478                            $this->log(__METHOD__ . ' Failed add point to user. ' . json_encode($pointParams) . ' -- ' . json_encode($data), $logFileName);
20479                            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed add point to user. ' . json_encode($pointParams) . ' -- ' . json_encode($data), 'error');
20480                            $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
20481                            return ;
20482                        }
20483                    }
20484                }
20485                // NJ-66191 Add logger for next_charge_date
20486                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Attempt to change next_charge_date --> ' . json_encode(['order_code' => $orderCode, 'old_next_charge_date' => $userData['next_charge_date'] ?? null, 'new_next_charge_date' => $saveUserArr['next_charge_date']]), $logFileName);
20487                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Attempt to change next_charge_date --> ' . json_encode(['order_code' => $orderCode, 'old_next_charge_date' => $userData['next_charge_date'] ?? null, 'new_next_charge_date' => $saveUserArr['next_charge_date']]), 'error');
20488
20489            } elseif ($formType == Configure::read('payment_credit_authentication')) {
20490                // set minutes and seconds to 00:00 always
20491                $nextChargeDate = date('Y-m-d H:00:00', strtotime('+' . $nextChargeTime . ' second ' . $this->User->getFirstNextChargeDate()));
20492                $saveUserArr['next_charge_date'] = $nextChargeDate;
20493                // NJ-66191 Add logger for next_charge_date
20494                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Attempt to change next_charge_date --> ' . json_encode(['order_code' => $orderCode, 'old_next_charge_date' => $userData['next_charge_date'] ?? null, 'new_next_charge_date' => $saveUserArr['next_charge_date']]), $logFileName);
20495                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Attempt to change next_charge_date --> ' . json_encode(['order_code' => $orderCode, 'old_next_charge_date' => $userData['next_charge_date'] ?? null, 'new_next_charge_date' => $saveUserArr['next_charge_date']]), 'error');
20496                
20497                if (isset($ptPaymentParams['userRegister']) && $ptPaymentParams['userRegister']) {
20498                    $stepKey = Configure::read('registration_steps.credit_card_registration_success');
20499                     $this->memcache->set(array(
20500                        'key' => 'wp_register_completed_'.$userId,
20501                        'value' => true,
20502                        'expire' => 120
20503                    ));
20504                    $this->saveStep($userId, $stepKey);
20505                }
20506            }
20507
20508            // if credit card change from android or apple to worldpay
20509            if (
20510                in_array($formType, array(Configure::read('payment_credit_change'), Configure::read('payment_credit_authentication'))) &&
20511                in_array($cardCompany, array(Configure::read('card_company.apple'), Configure::read('card_company.google')))
20512            ) {
20513
20514
20515                $pointParams = array(
20516                    'userId' => $userId,
20517                    'point' => 500,
20518                    'kbn' => 6,
20519                    'kbnType' => 1, // add coin
20520                    'coinType' => 2, // service coin
20521                    'coinFailMessage' => Configure::read('coin.failed.campaign')
20522                );
20523
20524                if (!$this->UsersPoint->performPointTransaction($pointParams)) {
20525                    $msg = 'Adding user coin history failed.';
20526                    $this->log(__METHOD__ . ' ' . $msg . ' Point params --> ' . json_encode($pointParams) . ' | kickback data --> ' . $dataJson, $logFileName);
20527                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' Point params --> ' . json_encode($pointParams) . ' | kickback data --> ' . $dataJson, 'error');
20528                    $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
20529                    throw new InternalErrorException($msg);
20530                }
20531            }
20532
20533            $famRegist = false;
20534            // NC-4673: update family parent_id, memo and monthly_payment
20535            
20536            if (
20537                in_array($formType, Configure::read('family_plan_form_types'))
20538            ) {
20539                // if parent_id is empty
20540                if (empty($userData['parent_id'])) {
20541                    $saveUserArr['parent_id'] = $parentId;
20542                    $saveUserArr['memo'] = date('Y/m/d H:i:s')." Family plan[User]: family registration \n".$userData['memo'];
20543                    $famRegist = true;
20544
20545                    if (empty($userData['currency_code'])) {
20546                        $saveUserArr['currency_code'] = $currencyCode;
20547                    }
20548                }
20549            }
20550
20551            // get and set card token, card brand and card number
20552            // if not new registration, delete wp token
20553            if (
20554                $formType == Configure::read('payment_credit_change') ||
20555                ($formType == Configure::read('payment_credit_authentication') && isset($ptPaymentParams['newCard']) && $ptPaymentParams['newCard']) ||
20556                ($formType == Configure::read('payment_credit_retry') && isset($ptPaymentParams['newCard']) && $ptPaymentParams['newCard']) ||
20557                ($formType == Configure::read('payment_credit_force_charge') && isset($ptPaymentParams['newCard']) && $ptPaymentParams['newCard']) ||
20558                $formType == Configure::read('payment_credit_family_free') ||
20559                $formType == Configure::read('payment_credit_family_monthly_payment')
20560            ) {
20561                // if family plan payment use parent id
20562                if($formType == Configure::read('payment_credit_family_free') || $formType == Configure::read('payment_credit_family_monthly_payment')){
20563                    $authenticatedShopperId = $parentId;
20564                }else{
20565                    $authenticatedShopperId = $userId;
20566                }
20567
20568                $cardInfoParams = array(
20569                    'merchantCode' => $merchantCode,
20570                    'authenticatedShopperId' => $authenticatedShopperId,
20571                    'xmlName' => 'card_info'
20572                );
20573
20574                $cardInfo = wpPaymentService::getUserCardInfo($cardInfoParams);
20575                $ptResponseText['getUserCardInfo_response'] = $cardInfo;
20576                $cardToken = null;
20577                $cardDetails = array();
20578
20579                // user has only 1 token
20580                if (isset($cardInfo['paymentService']['reply']['token']['tokenDetails'])) {
20581                    $cardTokenDetails = $cardInfo['paymentService']['reply']['token']['tokenDetails'];
20582                    $cardToken = $cardTokenDetails['paymentTokenID'];
20583
20584                    // get card number and card brand
20585                    $cardDetails = isset($cardInfo['paymentService']['reply']['token']['paymentInstrument']['cardDetails']['derived']) ? $cardInfo['paymentService']['reply']['token']['paymentInstrument']['cardDetails']['derived'] : array();
20586
20587                    // - if has no card details, check other payment instru
20588                    if (!$cardDetails) {
20589                        // - paypal
20590                        if (isset($cardInfo['paymentService']['reply']['token']['paymentInstrument']['paypal']['derived'])) {
20591                            $cardDetails = $cardInfo['paymentService']['reply']['token']['paymentInstrument']['paypal']['derived'];
20592                        }
20593
20594                        // - emvco token
20595                        if (isset($cardInfo['paymentService']['reply']['token']['paymentInstrument']['emvcoTokenDetails']['derived'])) {
20596                            $cardDetails = $cardInfo['paymentService']['reply']['token']['paymentInstrument']['emvcoTokenDetails']['derived'];
20597                        }
20598
20599                        // - sepa
20600                        if (isset($cardInfo['paymentService']['reply']['token']['paymentInstrument']['sepa']['derived'])) {
20601                            $cardDetails = $cardInfo['paymentService']['reply']['token']['paymentInstrument']['sepa']['derived'];
20602                        }
20603                    }
20604
20605                    // NJ-62324
20606                    // If change card, and old card details is the same as new one, update user token
20607                    $newCardNumber = substr($cardDetails['obfuscatedPAN'], -4);
20608                    $newCardBrand = $cardDetails['cardBrand'];
20609                    $oldCardNumber = isset($userData['card_number']) ? $userData['card_number'] : 0;
20610                    $oldCardBrand = isset($userData['card_brand']) ? $userData['card_brand'] : 0;
20611                    $oldCardToken = isset($userData['card_token']) ? $userData['card_token'] : 0;
20612
20613                    $expiryMonth = isset($cardInfo['paymentService']['reply']['token']['paymentInstrument']['cardDetails']['expiryDate']['date']['@month']) ? $cardInfo['paymentService']['reply']['token']['paymentInstrument']['cardDetails']['expiryDate']['date']['@month'] : null;
20614                    $expiryYear = isset($cardInfo['paymentService']['reply']['token']['paymentInstrument']['cardDetails']['expiryDate']['date']['@year']) ? $cardInfo['paymentService']['reply']['token']['paymentInstrument']['cardDetails']['expiryDate']['date']['@year'] : null;
20615
20616                    // NJ-62324: for debugging
20617                    $debugWPayTokenData = array(
20618                        'newCardNumber' => $newCardNumber,
20619                        'newCardBrand' => $newCardBrand,
20620                        'oldCardNumber' => $oldCardNumber,
20621                        'oldCardBrand' => $oldCardBrand,
20622                        'oldCardToken' => $oldCardToken,
20623                        'newCardToken' => $cardToken,
20624                        'expiryMonth' => $expiryMonth,
20625                        'expiryYear' => $expiryYear
20626                    );
20627                    $this->log(__METHOD__ . ' Reply Worldpay Update Token Data Attempt -> ' . $authenticatedShopperId . ' -> ' . json_encode($debugWPayTokenData), $logFileName);
20628
20629                    if (
20630                        $expiryMonth && $expiryYear && 
20631                        ( ($newCardNumber == $oldCardNumber && $newCardBrand == $oldCardBrand) || ($cardToken == $oldCardToken) )
20632                    ) {
20633                        // always 2 digits, example 01, 02, 03
20634                        $expiryMonth = str_pad($expiryMonth, 2, '0', STR_PAD_LEFT); 
20635                        $updateTokenParams = array(
20636                            'merchantCode' => $merchantCode,
20637                            'paymentTokenId' => $cardToken,
20638                            'authenticatedShopperId' => $userId,
20639                            'xmlName' => 'update_token',
20640                            'expiryMonth' => $expiryMonth,
20641                            'expiryYear' => $expiryYear,
20642                            'orderCode' => $orderCode,
20643                            'tokenReason' => 'Payment Credit Change'
20644                        );
20645                        $ptResponseText['updateUserToken_request'][] = $updateTokenParams;
20646                        $this->log(__METHOD__ . ' New Expiry Date Update Token -> ' . $authenticatedShopperId . ' -> ' . json_encode($updateTokenParams), $logFileName);
20647
20648                        // update latest token only
20649                        $ptResponseText['updateUserToken_response'][] =  $this->updateUserToken(array(
20650                            'updateTokenParams' => $updateTokenParams,
20651                            'logFileName' => $logFileName,
20652                            'dataJson' => $dataJson,
20653                            'ptId' => $paymentTransactionData['id']
20654                        ));
20655                    }
20656
20657                // user has many token
20658                } elseif (isset($cardInfo['paymentService']['reply']['token'][0])) {
20659                    $cardTokenDetails = $cardInfo['paymentService']['reply']['token'];
20660
20661                    $getCardDetailFlg = 0;
20662                    $countTokenDetails = count($cardTokenDetails) - 1;
20663                    foreach ($cardTokenDetails as $key => $value) {
20664                        if (
20665                            (
20666                                $formType == Configure::read('payment_credit_change') && 
20667                                (isset($ptPaymentParams['newCard']) && $ptPaymentParams['newCard']) && 
20668                                (isset($ptPaymentParams['cardToken']) && $ptPaymentParams['cardToken']) &&
20669                                $value['tokenDetails']['paymentTokenID'] != $ptPaymentParams['cardToken'] &&
20670                                $getCardDetailFlg == 0
20671                            ) || 
20672                            (
20673                                $formType == Configure::read('payment_credit_change') &&
20674                                $key == $countTokenDetails && 
20675                                $getCardDetailFlg == 0
20676                            )
20677                        ) {
20678                            
20679                            // - get card details
20680                            $cardToken = $value['tokenDetails']['paymentTokenID'];
20681                            $cardDetails = isset($value['paymentInstrument']['cardDetails']['derived']) ? $value['paymentInstrument']['cardDetails']['derived'] : array();
20682                            
20683                            // - if has no card details, check other payment instru
20684                            if (!$cardDetails) {
20685                                // - paypal
20686                                if (isset($cardInfo['paymentService']['reply']['token']['paymentInstrument']['paypal']['derived'])) {
20687                                    $cardDetails = $cardInfo['paymentService']['reply']['token']['paymentInstrument']['paypal']['derived'];
20688                                }
20689
20690                                // - emvco token
20691                                if (isset($cardInfo['paymentService']['reply']['token']['paymentInstrument']['emvcoTokenDetails']['derived'])) {
20692                                    $cardDetails = $cardInfo['paymentService']['reply']['token']['paymentInstrument']['emvcoTokenDetails']['derived'];
20693                                }
20694                                
20695                                // - sepa
20696                                if (isset($cardInfo['paymentService']['reply']['token']['paymentInstrument']['sepa']['derived'])) {
20697                                    $cardDetails = $cardInfo['paymentService']['reply']['token']['paymentInstrument']['sepa']['derived'];
20698                                }
20699                            }
20700                            $getCardDetailFlg = 1;
20701
20702                            // NJ-62324
20703                            // If change card, and old card details is the same as new one, update latest token only
20704                            $newCardNumber = substr($cardDetails['obfuscatedPAN'], -4);
20705                            $newCardBrand = $cardDetails['cardBrand'];
20706                            $oldCardNumber = isset($userData['card_number']) ? $userData['card_number'] : 0;
20707                            $oldCardBrand = isset($userData['card_brand']) ? $userData['card_brand'] : 0;
20708                            $oldCardToken = isset($userData['card_token']) ? $userData['card_token'] : 0;
20709
20710                            $expiryMonth = isset($value['paymentInstrument']['cardDetails']['expiryDate']['date']['@month']) ? $value['paymentInstrument']['cardDetails']['expiryDate']['date']['@month'] : null;
20711                            $expiryYear = isset($value['paymentInstrument']['cardDetails']['expiryDate']['date']['@year']) ? $value['paymentInstrument']['cardDetails']['expiryDate']['date']['@year'] : null;
20712    
20713                            // NJ-62324: for debugging
20714                            $debugWPayTokenData = array(
20715                                'newCardNumber' => $newCardNumber,
20716                                'newCardBrand' => $newCardBrand,
20717                                'oldCardNumber' => $oldCardNumber,
20718                                'oldCardBrand' => $oldCardBrand,
20719                                'oldCardToken' => $oldCardToken,
20720                                'newCardToken' => $cardToken,
20721                                'expiryMonth' => $expiryMonth,
20722                                'expiryYear' => $expiryYear
20723                            );
20724                            $this->log(__METHOD__ . ' Reply Worldpay Update Token Data Attempt -> ' . $authenticatedShopperId . ' -> ' . json_encode($debugWPayTokenData), $logFileName);
20725
20726                            if (
20727                                $expiryMonth && $expiryYear && 
20728                                ( ($newCardNumber == $oldCardNumber && $newCardBrand == $oldCardBrand) || ($cardToken == $oldCardToken) )
20729                            ) {
20730                                // always 2 digits, example 01, 02, 03
20731                                $expiryMonth = str_pad($expiryMonth, 2, '0', STR_PAD_LEFT); 
20732                                $updateTokenParams = array(
20733                                    'merchantCode' => $merchantCode,
20734                                    'paymentTokenId' => $cardToken,
20735                                    'authenticatedShopperId' => $userId,
20736                                    'xmlName' => 'update_token',
20737                                    'expiryMonth' => $expiryMonth,
20738                                    'expiryYear' => $expiryYear,
20739                                    'orderCode' => $orderCode,
20740                                    'tokenReason' => 'Payment Credit Change'
20741                                );
20742                                $ptResponseText['updateUserToken_request'][] = $updateTokenParams;
20743                                $this->log(__METHOD__ . ' New Expiry Date -> ' . $authenticatedShopperId . ' -> '. json_encode($updateTokenParams), $logFileName);
20744    
20745                                // update latest token only
20746                                $ptResponseText['updateUserToken_response'][] =  $this->updateUserToken(array(
20747                                    'updateTokenParams' => $updateTokenParams,
20748                                    'logFileName' => $logFileName,
20749                                    'dataJson' => $dataJson,
20750                                    'ptId' => $paymentTransactionData['id']
20751                                ));
20752                            }
20753
20754
20755                        } else if ($key == 0 && $formType != Configure::read('payment_credit_change')) { // NC-5642 : get the first wp token.
20756                            $cardToken = $value['tokenDetails']['paymentTokenID'];
20757                            $cardDetails = isset($value['paymentInstrument']['cardDetails']['derived']) ? $value['paymentInstrument']['cardDetails']['derived'] : array();
20758                            
20759                            // - if has no card details, check other payment instru
20760                            if (!$cardDetails) {
20761                                // - paypal
20762                                if (isset($cardInfo['paymentService']['reply']['token']['paymentInstrument']['paypal']['derived'])) {
20763                                    $cardDetails = $cardInfo['paymentService']['reply']['token']['paymentInstrument']['paypal']['derived'];
20764                                }
20765
20766                                // - emvco token
20767                                if (isset($cardInfo['paymentService']['reply']['token']['paymentInstrument']['emvcoTokenDetails']['derived'])) {
20768                                    $cardDetails = $cardInfo['paymentService']['reply']['token']['paymentInstrument']['emvcoTokenDetails']['derived'];
20769                                }
20770                                
20771                                // - sepa
20772                                if (isset($cardInfo['paymentService']['reply']['token']['paymentInstrument']['sepa']['derived'])) {
20773                                    $cardDetails = $cardInfo['paymentService']['reply']['token']['paymentInstrument']['sepa']['derived'];
20774                                }
20775                            }
20776                            $getCardDetailFlg = 1;
20777
20778                        // delete user useless token(s)
20779                        } else {
20780                            $ptResponseText['deleteUserToken_response'][] = $this->deleteUserToken(array(
20781                                'deleteTokenParams' => array(
20782                                    'merchantCode' => $merchantCode,
20783                                    'paymentTokenId' => $value['tokenDetails']['paymentTokenID'],
20784                                    'authenticatedShopperId' => $userId,
20785                                    'xmlName' => 'delete_token'
20786                                ),
20787                                'logFileName' => $logFileName,
20788                                'dataJson' => $dataJson,
20789                                'ptId' => $paymentTransactionData['id']
20790                            ));
20791                        }
20792                    }
20793                }
20794                
20795                // update payment transaction if can't generate card info and return
20796                if (!$cardToken || !$cardDetails) {
20797                    $msg = 'Failed to generate card info.';
20798                    $this->log(__METHOD__ . ' ' . $msg . ' params --> ' . json_encode($cardInfoParams) . ", error(s) --> " . json_encode($cardInfo) .' | kickback data --> ' . $dataJson, $logFileName);
20799                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' params --> ' . json_encode($cardInfoParams) . ", error(s) --> " . json_encode($cardInfo) .' | kickback data --> ' . $dataJson, 'error');
20800                    $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
20801                    throw new InternalErrorException($msg);
20802                } else {
20803                    // set card token
20804                    $saveUserArr['card_token'] = $cardToken;
20805
20806                    // set card brand
20807                    $saveUserArr['card_brand'] = $cardDetails['cardBrand'];
20808
20809                    // set card number
20810                    $saveUserArr['card_number'] = substr($cardDetails['obfuscatedPAN'], -4);
20811                }
20812            }
20813
20814            // campaign master trigger 2
20815            if (
20816                $formType == Configure::read('payment_credit_monthly_payment') && 
20817                $userData['payment_plan_id'] == Configure::read('payment_plans.free_trial')
20818            ) {
20819                UsersPointTable::giveBonusCoins(['userId' => $userId, 'triggerNo' => 2]);
20820            }
20821
20822            // update user data
20823            $uModel->clear();
20824            $uModel->recursive = -1;
20825            $read = $uModel->read(array_keys($saveUserArr), $userId);
20826            $uModel->validate = array();
20827            $uModel->set($saveUserArr);
20828            if (!$uModel->save()) {
20829                $msg = 'Updating user failed.';
20830                $this->log(__METHOD__ . ' ' . $msg . ' User data --> ' . json_encode($saveUserArr) . ' | kickback data --> ' . $dataJson, $logFileName);
20831                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' User data --> ' . json_encode($saveUserArr) . ' | kickback data --> ' . $dataJson, 'error');
20832                $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
20833                throw new InternalErrorException($msg);
20834            }
20835
20836            // check if membership status was change
20837            if (isset($ptPaymentParams['statusBefore']) && isset($ptPaymentParams['statusAfter']) && isset($ptPaymentParams['platform'])) {
20838                $currentUser = $this->User->find('first', array(
20839                    'fields' => array('User.parent_id', 'User.currency_code', 'User.payment_plan_id'),
20840                    'conditions' => array('User.id' => $userId),
20841                    'recursive' => -1
20842                ));
20843                $parentId = $currentUser['User']['parent_id'];
20844                $is_cron = 0;
20845                if (php_sapi_name() == 'cli' || $ptPaymentParams['logFileName'] == 'retry_monthly_payment'){
20846                    $is_cron = 1;
20847                } 
20848                   $currency_after = $currentUser['User']['currency_code'];
20849                   $plan_after = $currentUser['User']['payment_plan_id'];
20850                $usclData = array(
20851                    'user_id' => $userId,
20852                    'platform' => $ptPaymentParams['platform'] ?? '',
20853                    'card_company_before' => $read['User']['card_company'],
20854                    'status_before' => $ptPaymentParams['statusBefore'],
20855                    'status_after' => $ptPaymentParams['statusAfter'],
20856                    'controller_name' => $this->request->params['controller'],
20857                    'action_name' => $this->request->params['action'],
20858                    'parent_id' => $parentId,
20859                    'is_cron' => $is_cron,
20860                    'currency_before' => $currency_before,
20861                    'currency_after' => $currency_after,
20862                    'payment_plan_id_before' => $plan_before,
20863                    'payment_plan_id_after' => $plan_after,
20864                    'default_appreciation_flg' => $appreciationFlg,
20865                    'default_appreciation_amount' => $tipAmount
20866                );
20867
20868                // save user change membership status
20869                if (!$this->UserStatusChangeLog->saveLog($usclData)) {
20870                    $msg = 'Saving user status change log failed.';
20871                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' --> ' . json_encode($usclData), 'error');
20872                    $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
20873                    throw new InternalErrorException($msg);
20874                }
20875            }
20876
20877            // NC-7459 check previus user status, add coinbox challenge
20878            if (
20879                isset($userData['payment_plan_id'])
20880                && $userData['payment_plan_id'] == Configure::read('payment_plans.complimentary_plan')
20881                && isset($userData['complimentary_code'])
20882            ) {
20883
20884                // get complimentary coin award
20885                $coinAward = $this->ComplimentaryCode->find('first', array(
20886                    'fields' => array('coin_award'),
20887                    'conditions' => array(
20888                        'ComplimentaryCode.code' => $userData['complimentary_code'],
20889                        'ComplimentaryCode.template_type !=' => 0 // Free trial
20890                    )
20891                ));
20892
20893                if (
20894                    isset($coinAward['ComplimentaryCode']['coin_award'])
20895                    && $coinAward['ComplimentaryCode']['coin_award']
20896                ) { // @TODO use common @note did not use CoinBox->addCoinReward because it will not succeed for unknown reason.
20897                    $coinboxSet = array(
20898                        'status' => 1,
20899                        'user_id' => $userId,
20900                        'teacher_id' => null,
20901                        'coin_event_id' => Configure::read('coin_box_event.complimentary'),
20902                        'coin' => $coinAward['ComplimentaryCode']['coin_award'],
20903                        'lesson_id' => NULL,
20904                        'expiration_date' => date('Y-m-d 23:59:59', strtotime('+59 days'))
20905                    );
20906                    $this->CoinBox->create();
20907                    $this->CoinBox->set($coinboxSet);
20908                    if (!$this->CoinBox->save()) {
20909                        $msg = 'Saving user coin box failed.';
20910                        $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' coin box data --> ' . json_encode($coinboxSet), 'error');
20911                        $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
20912                        throw new InternalErrorException($msg);
20913                    }
20914                }
20915            }
20916
20917            // if parent user update children's card company
20918            if ($formType == Configure::read('payment_credit_change')) {
20919                $childList = $this->User->getChildId($userId);
20920                // check if user is parent
20921                if (!empty($childList)) {
20922                    foreach ($childList as $childId) {
20923                        $this->User->clear();
20924                        $updateCCArr = array('card_company' => $cardCompany);
20925                        if (!$this->User->read(array_keys($updateCCArr), $childId)) {
20926                            $this->log(__METHOD__ . ' child id does not exist.  --> ' . json_encode($updateCCArr) . ' | parent id --> ' . $userId . ' | wp data --> ' . json_encode($ptPaymentParams), $logFileName);
20927                            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - child id does not exist.  --> ' . json_encode($updateCCArr) . ' | parent id --> ' . $userId . ' | wp data --> ' . json_encode($ptPaymentParams), 'error');
20928                            return ;
20929                        }
20930
20931                        $this->User->set($updateCCArr);
20932                        if (!$this->User->save()) {
20933                            $this->log(__METHOD__ . ' failed to update child card company.   --> ' . json_encode($updateCCArr) . ' | parent id --> ' . $userId . ' | wp data --> ' . json_encode($ptPaymentParams), $logFileName);
20934                            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - failed to update child card company.   --> ' . json_encode($updateCCArr) . ' | parent id --> ' . $userId . ' | wp data --> ' . json_encode($ptPaymentParams), 'error');
20935                            return ;
20936                        }
20937                    }
20938                }
20939            }
20940
20941            $memKey = 'family_reactivation_' . $parentId . '_' . $familyId;
20942            $familyReactivation = $this->memcache->get($memKey);
20943
20944            // NC-3754 : add memo for reactivation parent user.
20945            if ($formType == Configure::read('payment_credit_family_monthly_payment') && !empty($userData['parent_id']) && $familyReactivation) {
20946                $famRegist = false;
20947                // delete memcache
20948                $this->memcache->delete($memKey);
20949                $this->User->clear();
20950                if (!$userRead = $this->User->read(array('memo'), $parentId)) {
20951                    $msg = 'User id does not exist';
20952                    $this->log(__METHOD__ . ' User id does not exist. ' . json_encode($ptPaymentParams), $logFileName);
20953                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - User id does not exist. ' . json_encode($ptPaymentParams), 'error');
20954                    $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
20955                    return ;
20956                }
20957
20958                $this->User->set(array('memo' => date('Y/m/d H:i:s')." Family plan[User]: family id: " . $userData['id'] . " reactivation \n" . $userRead['User']['memo']));
20959                $this->User->validate = false;
20960                if (!$this->User->save()) {
20961                    $msg = 'User id does not exist';
20962                    $this->log(__METHOD__ . ' Failed update user data. ' . json_encode($userRead) . ' -- ' . json_encode($ptPaymentParams), $logFileName);
20963                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed update user data. ' . json_encode($userRead) . ' -- ' . json_encode($ptPaymentParams), 'error');
20964                    $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
20965                    return ;
20966                }
20967            }
20968            
20969            // Proccess Family Plan
20970            if($famRegist && !$familyReactivation) {
20971                // @param:  parent id. for memcache key.
20972                $famPlanRes = $this->FamilyPlanList->processFamPlan($parentId, $familyId, $orderCode);
20973                if ($famPlanRes != "[OK]") {
20974                    $msg = 'Failed processing family plan.';
20975                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' - parentId --> ' . json_encode($parentId) . ' - familyId --> ' . json_encode($familyId) . ' - orderCode --> ' . json_encode($orderCode), 'error');
20976                    $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
20977                    return;
20978                }
20979            }
20980            
20981            // check if user's status is temporary
20982            if (
20983                $userData['status'] == 0 && 
20984                (
20985                    $formType == Configure::read('payment_credit_authentication') || 
20986                    $formType == Configure::read('payment_credit_family_monthly_payment') || 
20987                    $formType == Configure::read('payment_credit_family_free')
20988                )
20989            ) {
20990                // update user's status after step 4
20991                $uModel->clear();
20992                $uModel->read(array('status'), $userId);
20993                $uModel->validate = array();
20994                $uModel->set('status', 1);
20995                if (!$uModel->save()) {
20996                    $msg = 'Failed to update user status into 1.';
20997                    $this->log(__METHOD__ . ' ' . $msg . ' User id --> ' . json_encode($userId) . ' | kickback data --> ' . $dataJson, $logFileName);
20998                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' User id --> ' . json_encode($userId) . ' | kickback data --> ' . $dataJson, 'error');
20999                    $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
21000                    throw new InternalErrorException($msg);
21001                }
21002            }
21003            
21004            // NC-7779 : check if user has chivox monthly test taken for the current month, and monthly_speaking_attended_flg ON,
21005            // turn Off the flag if users has not yet taken the exam for the current month.
21006            if (
21007                isset($userData['monthly_speaking_attended_flg']) && isset($userData['monthly_speaking_business_attended_flg'])
21008                && ($userData['monthly_speaking_attended_flg'] == 1 || $userData['monthly_speaking_business_attended_flg'] == 1)
21009            ) {
21010                // check chivox monthly
21011                $paymentPlanIdsForChivoxMonthly = Configure::read('chivox.monthly.user_payment_plan_cantake_exam');
21012                if (in_array($paymentPlanId, $paymentPlanIdsForChivoxMonthly)) {
21013
21014                    // load model
21015                    $this->loadModel("UsersChivoxMonthlyTest");
21016                    $userTestMonthFlagParams['user_id'] = $userId;
21017                    $userTestMonthFlag = $this->UsersChivoxMonthlyTest->checkUserCurrentMonthExam($userTestMonthFlagParams);
21018
21019                    $monthly_speaking_attended_flg = Configure::read('chivox.test_data_test_type.daily'); // test_type daily speaking 0
21020                    $monthly_speaking_business_attended_flg = Configure::read('chivox.test_data_test_type.business'); // test_type business 1
21021                    $fieldsToUpdate = array();
21022
21023                    // if user hat not yet taken the exam for current month
21024                    if (!in_array($monthly_speaking_attended_flg, $userTestMonthFlag)) {
21025                        $fieldsToUpdate['monthly_speaking_attended_flg'] = 0;
21026                    }
21027                    if (!in_array($monthly_speaking_business_attended_flg, $userTestMonthFlag)) {
21028                        $fieldsToUpdate['monthly_speaking_business_attended_flg'] = 0;
21029                    }
21030
21031                    if ($fieldsToUpdate) {
21032                        $uModel->clear();
21033                        $uModel->recursive = -1;
21034                        $uModel->read(array_keys($fieldsToUpdate), $userId);
21035                        $uModel->validate = array();
21036                        $uModel->set($fieldsToUpdate);
21037                        if (!$uModel->save()) {
21038                            $msg = 'Failed to update user monthly_speaking_attended_flg into 0.';
21039                            $this->log(__METHOD__ . ' ' . $msg . ' User id --> ' . json_encode($userId) . ' | kickback data --> ' . $dataJson, $logFileName);
21040                            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' User id --> ' . json_encode($userId) . ' | kickback data --> ' . $dataJson, 'error');
21041                            $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
21042                            throw new InternalErrorException($msg);
21043                        }
21044                    }
21045                }
21046            }
21047        }
21048
21049        // if purchase coin
21050        if ($formType == Configure::read('payment_credit_coin_purchase') && isset($ptPaymentParams['coinPurchasePoints'])) {
21051            // change user id to child id
21052            if($familyId){
21053                $pointParamsUserId = $familyId;
21054            }else{
21055                $pointParamsUserId = $userId;
21056            }
21057
21058            $coinPurchasePoints = intVal($ptPaymentParams['coinPurchasePoints']);
21059            $coinData = $this->UsersPoint->SET_charge_overseas_menue($coinPurchasePoints, $currencyCode);
21060            
21061            // NC-5007 add to the user's existing coin
21062            $pcWorldPay = array(
21063                'userId' => $pointParamsUserId,
21064                'point' => $coinData['num_of_coin'] - $coinData['bonus_coin'],
21065                'kbn' => 7,
21066                'kbnType' => 1, // add coin
21067                'coinType' => 1, // purchase coin
21068                'coinFailMessage' => Configure::read('coin.failed.buy_coin'),
21069                'device' => isset($ptPaymentParams['device']) ? $ptPaymentParams['device'] : null
21070            );
21071
21072            $scWorldPay = array(
21073                'userId' => $pointParamsUserId,
21074                'point' => $coinData['bonus_coin'],
21075                'kbn' => 7,
21076                'kbnType' => 1, // add coin
21077                'coinType' => 2, // service coin
21078                'coinFailMessage' => Configure::read('coin.failed.buy_coin'),
21079                'device' => isset($ptPaymentParams['device']) ? $ptPaymentParams['device'] : null
21080            );
21081
21082            $pointParams = [$pcWorldPay, $scWorldPay];
21083
21084            if ( $pointParams ) {
21085                foreach($pointParams as $key => $val) {
21086                    if (!$this->UsersPoint->performPointTransaction($val)) {
21087                        $msg = 'Adding user coin history failed.';
21088                        $this->log(__METHOD__ . ' ' . $msg . json_encode($val) . ' -- ' . $dataJson, $logFileName);
21089                        $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . json_encode($val) . ' -- ' . $dataJson, 'error');
21090                        $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
21091                        throw new InternalErrorException($msg);
21092                    }
21093                }
21094            }
21095        }
21096
21097        // [WorldPay] check if receivable payment sent was either
21098        // receivable payment, monthly payment, force settlement, or retry payment or payment change
21099        // if yes, set receivable payments to "received"
21100        if (
21101            in_array($formType, array(
21102                Configure::read('payment_credit_appreciation_receivable'),
21103                Configure::read('payment_credit_receivable'),
21104                Configure::read('payment_credit_monthly_payment'),
21105                Configure::read('payment_credit_force_charge'),
21106                Configure::read('payment_credit_retry'),
21107                Configure::read('payment_credit_family_monthly_payment')
21108            )) ||
21109            (
21110                $formType == Configure::read('payment_credit_change') &&
21111                (
21112                    $receivablePayment ||
21113                    $appreciationReceivable ||
21114                    $liveLessonReceivable
21115                )
21116            )
21117        ) {
21118            // create new payment receivable
21119            if ($formType != Configure::read('payment_credit_receivable') && $receivablePayment) {
21120                // set payment id
21121                $data["payment_id"] = $paymentId;
21122
21123                // set variables
21124                $paymentData = array(
21125                    'user_id' => $userId,
21126                    'type_id' => $typeId,
21127                    'reference_id' => $userId,
21128                    'status' => $paymentStatus,
21129                    'form_type' => Configure::read('payment_credit_receivable'),
21130                    'ordd' => $orderCode,
21131                    'amount' => $receivablePayment,
21132                    'param1' => $dataJson,
21133                    'card_company' => $cardCompany,
21134                    'transaction_code' => $orderCode,
21135                    'currency_code' => $currencyCode,
21136                    'payment_id' => $paymentPlanId,
21137                    'price_id' => $priceId,
21138                    'payment_type' => $paymentType,
21139                    'discounted_amount' => 0
21140                );
21141
21142                // create new payment
21143                $pModel->clear();
21144                $pModel->create();
21145                $pModel->validate = array();
21146                $pModel->set($paymentData);
21147
21148                if (!$pModel->save()) {
21149                    $msg = 'Saving payment receivable failed.';
21150                    $this->log(__METHOD__ . ' ' . $msg . ' Params --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, $logFileName);
21151                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' - new payment receivable - Params --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, 'error');
21152                    $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
21153                    throw new InternalErrorException($msg);
21154                }
21155                //update/add user`s settlement amount
21156                $this->User->updateUserPayments($paymentData);
21157                // set payment_id
21158                $paymentId = $pModel->id;
21159
21160            }
21161
21162            // set payment receivable statuses to 2 - received
21163            $this->PaymentReceivable->updateReceivableReservationPayment(
21164                $userId, 
21165                array(
21166                    'status' => 2,
21167                    'payment_id' => $paymentId,
21168                    'payment_collection_date' => $dateNow,
21169                    'card_company' => $cardCompany,
21170                    'payment_plan_id' => $paymentPlanId,
21171                    'membership_type_index' => $membershipStatusIndex
21172                ),
21173                array(
21174                    'PaymentReceivable.user_id' => $userId,
21175                    'PaymentReceivable.status' => 0,
21176                    'PaymentReceivable.payment_element_type' => 1,
21177                    'PaymentReceivable.created <=' => $cronDateRun
21178                )
21179            );
21180
21181            // create new appreciation lesson payment receivable
21182            if ($formType != Configure::read('payment_credit_appreciation_receivable') && $appreciationReceivable > 0) {
21183                // set payment id
21184                $data["payment_id"] = $paymentId;
21185                //reset payment data
21186                $paymentData = array();
21187
21188                // set variables
21189                $paymentData = array(
21190                    'user_id' => $userId,
21191                    'type_id' => $typeId,
21192                    'reference_id' => $userId,
21193                    'status' => $paymentStatus,
21194                    'form_type' => Configure::read('appreciation_data.payment_form_type'),
21195                    'ordd' => $orderCode,
21196                    'amount' => $appreciationReceivable,
21197                    'param1' => $dataJson,
21198                    'card_company' => $cardCompany,
21199                    'transaction_code' => $orderCode,
21200                    'currency_code' => $currencyCode,
21201                    'payment_id' => $paymentPlanId,
21202                    'price_id' => $priceId,
21203                    'payment_type' => $paymentType,
21204                    'discounted_amount' => 0
21205                );
21206
21207                // create new payment
21208                $pModel->clear();
21209                $pModel->create();
21210                $pModel->validate = array();
21211                $pModel->set($paymentData);
21212
21213                if (!$pModel->save()) {
21214                    $msg = 'Saving appreciation payment receivable failed.';
21215                    $this->log(__METHOD__ . ' ' . $msg . ' Params --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, $logFileName);
21216                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' Params --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, 'error');
21217                    $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
21218                    throw new InternalErrorException($msg);
21219                }
21220                //update/add user`s settlement amount
21221                $this->User->updateUserPayments($paymentData);
21222                // set payment_id
21223                $paymentId = $pModel->id;
21224    
21225            }
21226
21227            // set payment receivable statuses to 2 - received
21228            $this->PaymentReceivable->updateReceivableReservationPayment(
21229                $userId, 
21230                array(
21231                    'status' => 2,
21232                    'payment_id' => $paymentId,
21233                    'payment_collection_date' => $dateNow,
21234                    'card_company' => $cardCompany,
21235                    'payment_plan_id' => $paymentPlanId,
21236                    'membership_type_index' => $membershipStatusIndex
21237                ),
21238                array(
21239                    'PaymentReceivable.user_id' => $userId,
21240                    'PaymentReceivable.status' => 0,
21241                    'PaymentReceivable.payment_element_type' => Configure::read('appreciation_data.payment_element_type'),
21242                    'PaymentReceivable.created <=' => $cronDateRun
21243                )
21244            );
21245
21246            // create new live lesson payment receivable
21247            if ($formType != Configure::read('payment_live_lesson_receivable') && $liveLessonReceivable) {
21248                // set payment id
21249                $data["payment_id"] = $paymentId;
21250
21251                // set variables
21252                $paymentData = array(
21253                    'user_id' => $userId,
21254                    'type_id' => $typeId,
21255                    'reference_id' => $userId,
21256                    'status' => $paymentStatus,
21257                    'form_type' => Configure::read('payment_live_lesson_receivable'),
21258                    'ordd' => $orderCode,
21259                    'amount' => $liveLessonReceivable,
21260                    'param1' => $dataJson,
21261                    'card_company' => $cardCompany,
21262                    'transaction_code' => $orderCode,
21263                    'currency_code' => $currencyCode,
21264                    'payment_id' => $paymentPlanId,
21265                    'price_id' => $priceId,
21266                    'payment_type' => $paymentType,
21267                    'discounted_amount' => 0
21268                );
21269
21270                // create new payment
21271                $pModel->clear();
21272                $pModel->create();
21273                $pModel->validate = array();
21274                $pModel->set($paymentData);
21275
21276                if (!$pModel->save()) {
21277                    $msg = 'Saving payment receivable failed.';
21278                    $this->log(__METHOD__ . ' ' . $msg . ' Params --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, $logFileName);
21279                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' - new live lesson payment receivable - Params --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, 'error');
21280                    $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
21281                    throw new InternalErrorException($msg);
21282                }
21283                //update/add user`s settlement amount
21284                $this->User->updateUserPayments($paymentData);
21285                // set payment_id
21286                $paymentId = $pModel->id;
21287            }
21288
21289            // set payment receivable statuses to 2 - received
21290            $this->PaymentReceivable->updateReceivableReservationPayment(
21291                $userId, 
21292                array(
21293                    'status' => 2,
21294                    'payment_id' => $paymentId,
21295                    'payment_collection_date' => $dateNow,
21296                    'card_company' => $cardCompany,
21297                    'payment_plan_id' => $paymentPlanId,
21298                    'membership_type_index' => $membershipStatusIndex
21299                ),
21300                array(
21301                    'PaymentReceivable.user_id' => $userId,
21302                    'PaymentReceivable.status' => 0,
21303                    'PaymentReceivable.payment_element_type' => Configure::read('payment_element_type.live'),
21304                    'PaymentReceivable.created <=' => $cronDateRun
21305                )
21306            );    
21307        }
21308
21309
21310        // NC-7029: CHECK REFERRAL USER
21311        if (
21312            in_array($formType, array(
21313                Configure::read('payment_credit_monthly_payment'),
21314                Configure::read('payment_credit_force_charge'),
21315                Configure::read('payment_credit_retry'),
21316                Configure::read('payment_credit_authentication')
21317            ))
21318        ) {
21319            $ruData = array(
21320                'referee_id' => $userId,
21321                'payment_plan_id' => $paymentPlanId,
21322                'currency_code' => $userData['currency_code'],
21323                'logFileName' => $logFileName,
21324                'form_type' => $formType
21325            );
21326
21327            $couponReferredData = $this->UsersReferral->checkReferredUser($ruData);
21328            if (isset($couponReferredData['error']) && $couponReferredData['error']) {
21329                $msg = 'Failed to update users referral event flg.';
21330                $this->log(__METHOD__ . ' ' . $msg . ' Params --> ' . json_encode($ruData) . ' | kickback data --> ' . $dataJson, $logFileName);
21331                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' Params --> ' . json_encode($ruData) . ' | kickback data --> ' . $dataJson, 'error');
21332                $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
21333                throw new InternalErrorException($msg);
21334            }
21335
21336            $couponMailId = Configure::read('site_in_mail.coupon_mail_template_id');
21337
21338            // send coupon mail to referee
21339            if (isset($couponReferredData['sendMailToReferee']) && $couponReferredData['sendMailToReferee']) {
21340                $refereeData = array(
21341                    'id' => $userData['id'],
21342                    'email' => $userData['email'],
21343                    'native_language2' => $userData['native_language2'],
21344                    'hash' => $userData['hash'],
21345                    'refereeName' => $userData['nickname'],
21346                    'referrerName' => $couponReferredData['referrerName'],
21347                    'couponAmount' => $couponReferredData['refereeSaveAmount'],
21348                    'couponUpdatedTotal' => $couponReferredData['refereeUpdatedTotal']
21349                );
21350
21351                // send mail to referee
21352                myMailer::sendTemplateMail($couponMailId, $userData['email'], $refereeData, array(), 'User');
21353            }
21354
21355            // send coupon mail to referer
21356            if (isset($couponReferredData['sendMailToReferer']) && $couponReferredData['sendMailToReferer']) {
21357                $referrerData = array(
21358                    'id' => $couponReferredData['referrerId'],
21359                    'email' => $couponReferredData['referrerEmail'],
21360                    'native_language2' => $couponReferredData['nativeLanguage2'],
21361                    'hash' => $couponReferredData['referrerHash'],
21362                    'refereeName' => $userData['nickname'],
21363                    'referrerName' => $couponReferredData['referrerName'],
21364                    'couponAmount' => $couponReferredData['refererSaveAmount'],
21365                    'couponUpdatedTotal' => $couponReferredData['refererUpdatedTotal']
21366                );
21367
21368                // send mail to referrer
21369                myMailer::sendTemplateMail($couponMailId, $couponReferredData['referrerEmail'], $referrerData, array(), 'User');
21370            }
21371
21372            // NJ-47740
21373            if (!empty($ptPaymentParams['monthlyDiscount']) && !empty($ptPaymentParams['monthly_grp_id'])) {
21374                $requestCouponConfirmData = array(
21375                    'grpId' => $ptPaymentParams['monthly_grp_id'],
21376                    'paymentId' => $paymentSaveID
21377                );
21378                
21379                $result_confirm = $this->UsersCouponV1->performCouponConfirm($requestCouponConfirmData);
21380                    
21381                if (!$result_confirm) {
21382                    $msg = 'Failed to confirm coupon use request.';
21383                    $this->log(__METHOD__ . ' Failed to confirm coupon use request. ' . json_encode($requestCouponConfirmData) . ' -- ' . $dataJson, $logFileName);
21384                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' ' . json_encode($requestCouponConfirmData) . ' -- ' . $dataJson, 'error');
21385                    $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
21386                }
21387            }
21388            
21389            //update/add user`s settlement amount
21390            if(!$this->User->updateUserPayments($paymentData)) {
21391                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to update user payments - REFERRAL USER --> ' . json_encode($paymentData), 'error');
21392            }
21393        } 
21394
21395        // if has native speaker payment
21396        // NJ-47740
21397        $getCouponDiscounDetail = PaymentTable::getCouponDiscountRequestDetail($ptPaymentParams, 'native');
21398        $nativeOptionDiscount = !empty($getCouponDiscounDetail['discounted_amount']) ? $getCouponDiscounDetail['discounted_amount'] : 0;
21399        $nativeCouponRequestId = !empty($getCouponDiscounDetail['coupon_request_id']) ? $getCouponDiscounDetail['coupon_request_id'] : null;
21400        if (
21401            isset($ptPaymentParams['nativeOptionPayment']) && ($ptPaymentParams['nativeOptionPayment'] > 0 || $nativeOptionDiscount > 0)
21402            && in_array($ptPaymentParams['formType'], array(Configure::read('payment_credit_monthly_payment'), Configure::read('payment_credit_family_monthly_payment')))
21403        ) {
21404            if(isset($ptPaymentParams['nativeOptionJoin']) && $ptPaymentParams['nativeOptionJoin']) {
21405                $nspFormType = Configure::read('payment_native_option_join');
21406            } else {
21407                $nspFormType = Configure::read('payment_native_option_monthly_payment');
21408            }
21409
21410            // check if family plan
21411            if ($familyId && $parentId) {
21412                // change reference id to parent id
21413                $referenceId = $parentId;
21414            } else {
21415                $referenceId = $userId;
21416            }
21417
21418            $paymentData = array(
21419                'user_id' => $userId,
21420                'type_id' => $typeId,
21421                'reference_id' => $referenceId,
21422                'payment_transaction_password' => $ptPassword,
21423                'status' => $paymentStatus,
21424                'form_type' => $nspFormType,
21425                'ordd' => $orderCode,
21426                'amount' => $ptPaymentParams['nativeOptionPayment'],
21427                'param1' => $dataJson,
21428                'card_company' => $cardCompany,
21429                'transaction_code' => $orderCode,
21430                'currency_code' => $currencyCode,
21431                'payment_id' => $paymentPlanId,
21432                'price_id' => $priceId,
21433                'payment_type' => Configure::read('payment_types.native_option'),
21434            );
21435            
21436            // NJ-47740
21437            $paymentData['discounted_amount'] = $nativeOptionDiscount;
21438            $paymentData['coupon_request_id'] = $nativeCouponRequestId;
21439
21440            // create new payment
21441            $pModel->clear();
21442            $pModel->create();
21443            $pModel->validate = array();
21444            $pModel->set($paymentData);
21445
21446            if (!$pModel->save()) {
21447                $msg = 'Saving payment receivable failed.';
21448                $this->log(__METHOD__ . ' ' . $msg . ' Params --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, $logFileName);
21449                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' - native speaker payment - Params --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, 'error');
21450                $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
21451                throw new InternalErrorException($msg);
21452            }
21453
21454            //update/add user`s settlement amount
21455            if(!$this->User->updateUserPayments($paymentData)) {
21456                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to update user payments - if has native speaker payment --> ' . json_encode($paymentData), 'error');
21457            }
21458            
21459            // NJ-47740
21460            if (!empty($paymentData['coupon_request_id']) && $paymentData['discounted_amount'] > 0) {
21461                // confirm coupon use request for native discount
21462                $requestCouponConfirmData = array(
21463                    'grpId' => $paymentData['coupon_request_id'],
21464                    'paymentId' => $pModel->id
21465                );
21466                $result_confirm = $this->UsersCouponV1->performCouponConfirm($requestCouponConfirmData);
21467                
21468                if (!$result_confirm) {
21469                    $msg = 'Failed to confirm native coupon use request.';
21470                    $this->log(__METHOD__ . ' Failed to confirm native coupon use request. ' . json_encode($requestCouponConfirmData) . ' -- ' . $dataJson, $logFileName);
21471                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to confirm native coupon use request. ' . json_encode($requestCouponConfirmData) . ' -- ' . $dataJson, 'error');
21472                    $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
21473                    throw new InternalErrorException($msg);
21474                }
21475            }
21476            // NJ-47740 end
21477            
21478            // update payment details
21479            $updatePaymentDetailParams = array(
21480                'currencyCode' => $paymentData['currency_code'],
21481                'formType' => $paymentData['form_type'],
21482                'paymentType' => $paymentData['payment_type'],
21483                'amount' => $paymentData['amount'],
21484                'discounted_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0,
21485                'familyId' => $familyId,
21486                'cronDateRun' => $cronDateRun,
21487                'priceId' => $paymentData['price_id'],
21488                'paymentPlanId' => $paymentData['payment_id'],
21489                'user_id' => $paymentData['user_id'],
21490                'coupon_use_request_id' => isset($paymentData['coupon_request_id']) ? $paymentData['coupon_request_id'] : null,
21491                'coupon_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0
21492            );
21493
21494            $updatePaymentDetail = array(
21495                'id' => $paymentTransactionData['id'],
21496                'fields' => array(
21497                    'payment_details' => $updatePaymentDetailParams
21498                )
21499            );
21500
21501            if (!$this->PaymentTransaction->updateWPPaymentTransaction($updatePaymentDetail)) {
21502                $this->log(__METHOD__ . ' Failed to update payment details. ' . json_encode($updatePaymentDetail), $logFileName);
21503                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to update payment details - if has native speaker payment ' . json_encode($updatePaymentDetail), 'error');
21504            }
21505        }
21506
21507        // if has callan option payment
21508        $getCouponDiscounDetail = PaymentTable::getCouponDiscountRequestDetail($ptPaymentParams, 'callan');
21509        $callanOptionDiscount = !empty($getCouponDiscounDetail['discounted_amount']) ? $getCouponDiscounDetail['discounted_amount'] : 0;
21510        $callanCouponRequestId = !empty($getCouponDiscounDetail['coupon_request_id']) ? $getCouponDiscounDetail['coupon_request_id'] : null;
21511        if (
21512            isset($ptPaymentParams['callanOptionPayment']) && ($ptPaymentParams['callanOptionPayment'] > 0 || $callanOptionDiscount > 0)
21513            && in_array($ptPaymentParams['formType'], array(Configure::read('payment_credit_monthly_payment'), Configure::read('payment_credit_family_monthly_payment')))
21514        ) {
21515            
21516            $nspFormType = Configure::read('payment_callan_option_monthly_payment');
21517            if(isset($ptPaymentParams['callanOptionJoin']) && $ptPaymentParams['callanOptionJoin']) {
21518                $nspFormType = Configure::read('payment_callan_option_join');
21519            }
21520
21521            // check if family plan
21522            if ($familyId && $parentId) {
21523                // change reference id to parent id
21524                $referenceId = $parentId;
21525            } else {
21526                $referenceId = $userId;
21527            }
21528
21529            $paymentData = array(
21530                'user_id' => $userId,
21531                'type_id' => $typeId,
21532                'reference_id' => $referenceId,
21533                'payment_transaction_password' => $ptPassword,
21534                'status' => $paymentStatus,
21535                'form_type' => $nspFormType,
21536                'ordd' => $orderCode,
21537                'amount' => $ptPaymentParams['callanOptionPayment'],
21538                'param1' => $dataJson,
21539                'card_company' => $cardCompany,
21540                'transaction_code' => $orderCode,
21541                'currency_code' => $currencyCode,
21542                'payment_id' => $paymentPlanId,
21543                'price_id' => $priceId,
21544                'payment_type' => Configure::read('payment_types.callan_option'),
21545            );
21546            
21547            // NJ-47740
21548            $paymentData['discounted_amount'] = $callanOptionDiscount;
21549            $paymentData['coupon_request_id'] = $callanCouponRequestId;
21550
21551            // create new payment
21552            $pModel->clear();
21553            $pModel->create();
21554            $pModel->validate = array();
21555            $pModel->set($paymentData);
21556
21557            if (!$pModel->save()) {
21558                $msg = 'Saving payment receivable failed.';
21559                $this->log(__METHOD__ . ' ' . $msg . ' Params --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, $logFileName);
21560                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg . ' - callan option payment - Params --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, 'error');
21561                $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
21562                throw new InternalErrorException($msg);
21563            }
21564
21565            //update/add user`s settlement amount
21566            $this->User->updateUserPayments($paymentData);
21567            
21568            // NJ-47740
21569            if (!empty($paymentData['coupon_request_id']) && $paymentData['discounted_amount'] > 0) {
21570                // confirm coupon use request for callan discount
21571                $requestCouponConfirmData = array(
21572                    'grpId' => $paymentData['coupon_request_id'],
21573                    'paymentId' => $pModel->id
21574                );
21575                $result_confirm = $this->UsersCouponV1->performCouponConfirm($requestCouponConfirmData);
21576                
21577                if (!$result_confirm) {
21578                    $msg = 'Failed to confirm callan coupon use request.';
21579                    $this->log(__METHOD__ . ' Failed to confirm callan coupon use request. ' . json_encode($requestCouponConfirmData) . ' -- ' . $dataJson, $logFileName);
21580                    $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to confirm callan coupon use request. ' . json_encode($requestCouponConfirmData) . ' -- ' . $dataJson, 'error');
21581                    $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
21582                    throw new InternalErrorException($msg);
21583                }
21584            }
21585            // NJ-47740 end
21586            
21587            // update payment details
21588            $updatePaymentDetailParams = array(
21589                'currencyCode' => $paymentData['currency_code'],
21590                'formType' => $paymentData['form_type'],
21591                'paymentType' => $paymentData['payment_type'],
21592                'amount' => $paymentData['amount'],
21593                'discounted_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0,
21594                'familyId' => $familyId,
21595                'cronDateRun' => $cronDateRun,
21596                'priceId' => $paymentData['price_id'],
21597                'paymentPlanId' => $paymentData['payment_id'],
21598                'user_id' => $paymentData['user_id'],
21599                'coupon_use_request_id' => isset($paymentData['coupon_request_id']) ? $paymentData['coupon_request_id'] : null,
21600                'coupon_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0
21601            );
21602
21603            $updatePaymentDetail = array(
21604                'id' => $paymentTransactionData['id'],
21605                'fields' => array(
21606                    'payment_details' => $updatePaymentDetailParams
21607                )
21608            );
21609
21610            if (!$this->PaymentTransaction->updateWPPaymentTransaction($updatePaymentDetail)) {
21611                $this->log(__METHOD__ . ' Failed to update payment details. ' . json_encode($updatePaymentDetail), $logFileName);
21612                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to update payment details. - if has callan option payment' . json_encode($updatePaymentDetail), 'error');
21613            }
21614        }
21615        
21616        // activate the user native option (new, resume, and monthly payment)
21617        if (isset($ptPaymentParams['nativeOptionPayment']) && ($ptPaymentParams['nativeOptionPayment'] > 0 || $nativenOptionDiscount > 0)) { 
21618            $this->log(__METHOD__ . ' NJ-2388 debug Payment Transaction Data: ' . json_encode($paymentTransactionData), 'native_option_debug');
21619            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - NJ-2388 debug Payment Transaction Data: ' . json_encode($paymentTransactionData), 'error');
21620
21621            // - option process data
21622            $optionProcessData = array(
21623                'user_id' => $userId,
21624                'type' => 'on',
21625                'option_type' => Configure::read('native_speaker.options.all_you_can_eat')
21626            );
21627            
21628            if(!$this->User->userNativeOptionProcess($optionProcessData)) {
21629                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Fail process on userNativeOptionProcess - nativeOptionPayment - data --> ' . json_encode($optionProcessData), 'error');
21630            }
21631
21632            //NJ-2814 add logs
21633            if (isset($ptPaymentParams['nativeOptionJoin']) && $ptPaymentParams['nativeOptionJoin']) {
21634                $nativeStatus = 1; // subscribed
21635                $statusBefore = '';
21636            } else {
21637                $nativeStatus = 2; // Monthly Continue
21638                $statusBefore = 1;
21639            }
21640
21641            $optionAfterName = 'Native Unlimited Option';
21642
21643            $optionLogParams = array(
21644                'user_id' => $userId,
21645                'platform' => $ptPaymentParams['platform'],
21646                'status' => $nativeStatus,
21647                'controller_name' => $this->request->params['controller'],
21648                'action_name' => $this->request->params['action'],
21649                'user_type' => 0, // user
21650                'option_before' => $statusBefore,
21651                'option_after' => 1,
21652                'option_before_name' => '',
21653                'option_after_name' => $optionAfterName,
21654                'option_type' => 1,
21655                'payment_plan_id' => $paymentPlanId
21656            );
21657
21658            if(!ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams)) {
21659                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed saving in saveOptionChangeLog - nativeOptionPayment - data --> ' . json_encode($optionLogParams), 'error');
21660            }
21661
21662            // - save registration status step
21663            $stepKey = Configure::read('registration_steps.user_info_entry');
21664            $this->saveStep($userId, $stepKey);
21665
21666        }
21667
21668        // activate the user native option (new, resume, and monthly payment)
21669        if (isset($ptPaymentParams['callanOptionPayment']) && ($ptPaymentParams['callanOptionPayment'] > 0 || $callanOptionDiscount > 0)) { 
21670            $this->log(__METHOD__ . ' NJ-2388 debug Payment Transaction Data: ' . json_encode($paymentTransactionData), 'native_option_debug');
21671
21672            // - option process data
21673            $optionProcessData = array(
21674                'user_id' => $userId,
21675                'type' => 'on',
21676                'option_type' => Configure::read('callan_unlimited.options.callan_unlimited_option')
21677            );
21678            if(!$this->User->userNativeOptionProcess($optionProcessData)) {
21679                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Fail process on userNativeOptionProcess - callanOptionPayment - data --> ' . json_encode($optionProcessData), 'error');
21680            }
21681
21682            //NJ-2814 add logs
21683            if (isset($ptPaymentParams['callanOptionJoin']) && $ptPaymentParams['callanOptionJoin']) {
21684                $callanStatus = 1; // subscribed
21685                $statusBefore = '';
21686            } else {
21687                $callanStatus = 2; // Monthly Continue
21688                $statusBefore = 1;
21689            }
21690
21691            $optionAfterName = 'Callan Unlimited Option';
21692
21693            $optionLogParams = array(
21694                'user_id' => $userId,
21695                'platform' => $ptPaymentParams['platform'],
21696                'status' => $callanStatus,
21697                'controller_name' => $this->request->params['controller'],
21698                'action_name' => $this->request->params['action'],
21699                'user_type' => 0, // user
21700                'option_before' => $statusBefore,
21701                'option_after' => 1,
21702                'option_before_name' => '',
21703                'option_after_name' => $optionAfterName,
21704                'option_type' => 2,
21705                'payment_plan_id' => $paymentPlanId
21706            );
21707
21708            if(!ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams)) {
21709                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed saving in saveOptionChangeLog - callanOptionPayment - data --> ' . json_encode($optionLogParams), 'error');
21710            }
21711        }
21712
21713        // update payment transaction payment id, status and response text
21714        $ptUpdate = $this->updatePaymentTransaction(array(
21715            'id' => $paymentTransactionData['id'],
21716            'fields' => array(
21717                'status' => 1, // done
21718                'payment_id' => $paymentId,
21719                'response_text' => $ptResponseText
21720            ),
21721            'logFileName' => $logFileName
21722        ));
21723
21724        if (!$ptUpdate) {
21725            $msg = 'Updating payment transaction failed.';
21726            $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - ' . $msg, 'error');
21727            $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
21728            throw new InternalErrorException($msg);
21729        }
21730
21731        // final save
21732
21733        // add registration bonus if user registration
21734        if (isset($ptPaymentParams['userRegister']) && $ptPaymentParams['userRegister']) {
21735
21736            UsersPointHistoryTable::checkDailyBonus($userId);
21737            $params = array(
21738                "type" => 1, // kickback
21739                "userID" => $userId,
21740                "userRegister" => true
21741            );
21742
21743            // add referral coin NC-9359
21744            $this->User->addReferralBonus($params);
21745
21746            // - get bonus coins on registration
21747            $receiveBonus = UsersPointTable::checkIfUserReceiveBonusUponRegister($userId);
21748            
21749            if (!$receiveBonus && empty($userData['complimentary_code'])) {
21750                $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - giveBonusCoins triggered', 'error');
21751                UsersPointTable::giveBonusCoins(['userId' => $userId, 'triggerNo' => 1]);
21752            }
21753        }
21754
21755        // campaign master trigger 5
21756        $this->retrial_confiscate_coins([
21757            'formType' => $formType,
21758            'paymentPlanId' => $paymentPlanId,
21759            'userId' => $userId
21760        ]);
21761
21762        // send event to adjust
21763        $adjustParams = array(
21764            'formType' => $formType,
21765            'statusBefore' => isset($ptPaymentParams['statusBefore']) ? $ptPaymentParams['statusBefore'] : null,
21766            'userId' => $userId
21767        );
21768        UserTable::sendEventToAdjust($adjustParams);
21769
21770        //NJ-23626 continuing plan campaign
21771        if (in_array($formType, array(Configure::read('payment_credit_retry'), Configure::read('payment_credit_monthly_payment')))){
21772            ClassRegistry::init('CampaignSettingTable')->takingLessonAndContinuePlan(array('user_id' => $userId, 'type' => 3));
21773        }
21774
21775        // - NJ-31307 : trigger campaign
21776        ClassRegistry::init('CampaignSettingTable')->callanUnlimitedCampaign(array(
21777            'user_id' => $userId, 
21778            'trigger' => 3, 
21779            'pt_params' => $paymentTransactionData ?? [],
21780            'payment_type' => 'Worldpay'
21781        ));
21782
21783        $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - DONE WP PROCESS --> ' . json_encode($data), 'error');
21784        echo "[OK]"; exit;
21785    }
21786
21787    /**
21788     * NC-4770: get user using request token and validate
21789     * @param array $params
21790     * @return array $userData
21791     */
21792    private function mobappGetUserData($params = array()) {
21793        $urlParams = myTools::getMobappToken($_GET);
21794
21795        if (!isset($params['logFileName']) || !isset($params['formType'])) {
21796            $this->log(__METHOD__ . ' Missing parameters(s). ' . json_encode($params), $logFileName);
21797            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
21798        }
21799
21800        $logFileName = $params['logFileName'];
21801        $formType = $params['formType'];
21802
21803        // redirect to retry page is param token is not set
21804        if (!isset($this->request->query['token']) || empty($this->request->query['token'])) {
21805            
21806            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
21807        }
21808        
21809        $apiToken = $this->request->query['token']; 
21810        $userParams = array(
21811            'fields' => array(
21812                'User.id',
21813                'User.status',
21814                'User.hash16',
21815                'User.hash',
21816                'User.native_language2',
21817                'User.email',
21818                'User.charge_flg',
21819                'User.parent_id',
21820                'User.fail_flg',
21821                'User.corporate_id',
21822                'User.corporate_type',
21823                'User.first_charge_date',
21824                'User.first_lesson_time',
21825                'User.monthly_payment',
21826                'User.card_token',
21827                'User.card_brand',
21828                'User.card_number',
21829                'User.api_token',
21830                'User.currency_code',
21831                'User.payment_plan_id',
21832                'User.price_id',
21833                'User.wp_transaction_identifier',
21834                'User.complimentary_code',
21835                'User.card_company',
21836                'User.double_check_flg',
21837                'User.platform',
21838                'User.idfa',
21839                'User.monthly_speaking_attended_flg',
21840                'User.monthly_speaking_business_attended_flg',
21841                'User.paypal_payer_id',
21842                'User.birthday',
21843                'PaymentPlanPrice.amount',
21844                'User.studysapuri_id',
21845                'User.nickname',
21846                'User.aftee_transaction_identifier',
21847                'User.phone_number',
21848                'User.sms_through_flg',
21849                'User.paypal_payer_id',
21850                'User.paypal_payer_email'
21851        ),
21852            'apiToken' => $apiToken
21853        );
21854
21855        // redirect to retry page if user does not exist using param token
21856        if (!$userData = $this->User->getWPMobappUserData($userParams)) {
21857            $this->log(__METHOD__ . ' User does not exist. ' . json_encode($userParams), $logFileName);
21858            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
21859        }
21860
21861        $user = new UserTable($userData['User']);
21862        $memberType = $user->getUserMembership();
21863
21864        // redirect to error page if settlement cron is currently on-going
21865        if (UserTable::checkPayingUser($user->id)) {
21866            return $this->redirect(myTools::getUrl() . '/mobapp/retry/error'.$urlParams);
21867        }
21868
21869        // redirect to retry page if currency code is null
21870        if (!isset($user->currency_code)) {
21871            $this->log(__METHOD__ . ' User currency code is null. ' . json_encode($user), $logFileName);
21872            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
21873        }
21874
21875        // if done paying using 3D secure, skip membership type checking
21876        $zeus3DSecureChallengeFlg = $this->memcache->get('zeus3DSecureChallengeFlg_' . $user->id);
21877        if ($zeus3DSecureChallengeFlg) {
21878            if (
21879                isset($user->complimentary_code) &&
21880                (
21881                    (isset($user->payment_plan_id) && $user->payment_plan_id == Configure::read('payment_plans.complimentary_plan')) ||
21882                    (!isset($user->payment_plan_id) && $this->Payment->ifComPlanUser($user->id))
21883                )
21884            ) {
21885                $userData['User']['com_plan_user'] = true;
21886            }
21887
21888            return $userData;
21889        }
21890
21891        switch($formType) {
21892            case Configure::read('payment_credit_retry'):
21893                if ($memberType != Configure::read('user.member_type_fail')) {
21894                    $this->log(__METHOD__ . ' User is not fail. result data --> ' . json_encode($userData), $logFileName);
21895                    return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
21896                }
21897                break;
21898            case Configure::read('payment_credit_authentication'):
21899                if ($memberType != Configure::read('user.member_type_free') && !$user->complimentary_code) {
21900                    $this->log(__METHOD__ . ' User charge_flg is not 0. result data --> ' . json_encode($userData), $logFileName);
21901                    return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
21902                }
21903                break;
21904            case Configure::read('payment_credit_force_charge'):
21905                if (
21906                    isset($user->complimentary_code) &&
21907                    (
21908                        (isset($user->payment_plan_id) && $user->payment_plan_id == Configure::read('payment_plans.complimentary_plan')) ||
21909                        (!isset($user->payment_plan_id) && $this->Payment->ifComPlanUser($user->id))
21910                    )
21911                ) {
21912                    $userData['User']['com_plan_user'] = true;
21913                    break;
21914                }
21915                // corporate light
21916                $corpType = myTools::getCoporateTypeUsingPaymentPlanId($user->payment_plan_id);
21917                if ( $corpType  == Configure::read("corporate_type.light") ) {
21918                    break;
21919                }
21920
21921
21922        }
21923
21924        return $userData;
21925    }
21926
21927    private function getRetryPaymentData($userData = array(), $logFileName = 'debug') {
21928        $result = array();
21929
21930        // if empty
21931        if (empty($userData)) {
21932            $this->log(__METHOD__. ' user data is empty ->' . json_encode($userData), $logFileName);
21933            return $result;
21934        }
21935
21936        // if empty currency code
21937        if (!isset($userData['currency_code'])) {
21938            $this->log(__METHOD__. ' user currency code is empty ->' . json_encode($userData), $logFileName);
21939            return $result;
21940        }
21941
21942        // if empty payment plan id
21943        if (!isset($userData['payment_plan_id'])) {
21944            $this->log(__METHOD__. ' user payment plan id is empty ->' . json_encode($userData), $logFileName);
21945            return $result;
21946        }
21947
21948        // if empty price id
21949        if (!isset($userData['price_id'])) {
21950            $this->log(__METHOD__. ' user price id is empty ->' . json_encode($userData), $logFileName);
21951            return $result;
21952        }
21953
21954        $currencyCode = $userData['currency_code'];
21955        $paymentPlanId = $userData['payment_plan_id'];
21956
21957        // - NJ-18780 : fetch the retry payment plan data based on the user current plan
21958          # check if is lite plan user 
21959        $isLitePlanUser = in_array($paymentPlanId, Configure::read('lite_payment_plans')) ? true : false;
21960
21961        //- NJ-27262 chocotto plan
21962        $isChocottoPlanUser = in_array($paymentPlanId, [Configure::read('payment_plans.free_trial_chocotto'), Configure::read('payment_plans.chocotto_plan')]);
21963
21964
21965        // if card company is equals to apple or google
21966        if (in_array($userData['card_company'], array(Configure::read('card_company.apple'), Configure::read('card_company.google')))) {
21967            return $this->PaymentPlanPrice->getPaymentData(array(
21968                'currencyCode' => $currencyCode,
21969                'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
21970                'logFileName' => $logFileName
21971            ));
21972        // if corporate user
21973        } elseif (isset($userData['corporate_id']) && $userData['corporate_id'] && isset($userData['payment_plan_id'])) {
21974            // get corporate plan data
21975            $cpData = $this->getCorporatePaymentPlan($userData);
21976
21977            // if empty
21978            if (!$cpData) {
21979                return $result;
21980            }
21981            
21982            return array(
21983                'amount' => $cpData['amount'],
21984                'fAmount' => $cpData['fAmount'],
21985                'priceId' => $cpData['priceId'],
21986                'paymentPlanId' => $cpData['paymentPlanId']
21987            );
21988        } else {
21989            // if free trial
21990            if ($paymentPlanId == Configure::read('payment_plans.free_trial')) {
21991                $firstChargeDate = $userData['first_charge_date'];
21992
21993                // if first charge date is null or is equals to '0000-00-00 00:00:00'
21994                if (!isset($firstChargeDate) || $firstChargeDate == '0000-00-00 00:00:00') {
21995                    // get first charge date using payment history
21996                    $paymentData = $this->Payment->find('first', array(
21997                        'fields' => array('created'),
21998                        'conditions' => array(
21999                            'form_type' => array(1,2,4,6),
22000                            'user_id' => $userData['id'],
22001                            'param2' => ''
22002                        ),
22003                        'order' => 'id DESC'
22004                    ));
22005
22006                    // if empty
22007                    if (!$paymentData) {
22008                        $this->log(__METHOD__ . ' User has no first charge payment data. --> ' . json_encode($userData), $logFileName);
22009                        return $result;
22010                    }
22011                    $firstChargeDate = $paymentData['Payment']['created'];
22012                }
22013
22014                // get premium payment plan
22015                $premiumPlanData = $this->PaymentPlanPrice->getPaymentData(array(
22016                    'currencyCode' => $currencyCode,
22017                    'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
22018                    'datetime' => $firstChargeDate,
22019                    'logFileName' => $logFileName
22020                ));
22021
22022                // if empty
22023                if (!$premiumPlanData) {
22024                    return $result;
22025                }
22026
22027                $amount = $premiumPlanData['amount'];
22028                $priceId = $premiumPlanData['priceId'];
22029                $planStartDate = $premiumPlanData['planStartDate'];
22030            } else {
22031                if ($isLitePlanUser) {
22032                    // get premium payment plan
22033                    $lightPlanData = $this->PaymentPlanPrice->getPaymentData(array(
22034                        'currencyCode' => $currencyCode,
22035                        'paymentPlanId' => Configure::read('payment_plans.light_plan'),
22036                        // 'datetime' => $userData['first_charge_date'],
22037                        'logFileName' => $logFileName
22038                    ));
22039
22040                    // if empty
22041                    if (!$lightPlanData) {
22042                        $this->log(__METHOD__. ' Payment plan price data does not exist. --> ' . json_encode($userData) . ' price id --> ' , json_encode($priceId), $logFileName);
22043                        return $result;
22044                    }
22045
22046                    $amount = $lightPlanData['amount'];
22047                    $priceId = $lightPlanData['priceId'];
22048                    $planStartDate = $lightPlanData['planStartDate'];
22049                } elseif ($isChocottoPlanUser) {
22050                    // get chocotto payment plan
22051                    $chocottoPlanData = $this->PaymentPlanPrice->getPaymentData(array(
22052                        'currencyCode' => $currencyCode,
22053                        'paymentPlanId' => Configure::read('payment_plans.chocotto_plan'),
22054                        'logFileName' => $logFileName
22055                    ));
22056
22057                    // if empty
22058                    if (!$chocottoPlanData) {
22059                        $this->log(__METHOD__. ' Payment plan price data does not exist. --> ' . json_encode($userData) . ' price id --> ' , json_encode($priceId), $logFileName);
22060                        return $result;
22061                    }
22062
22063                    $amount = $chocottoPlanData['amount'];
22064                    $priceId = $chocottoPlanData['priceId'];
22065                    $planStartDate = $chocottoPlanData['planStartDate'];
22066                } else {
22067                    // get user payment plan
22068                    $data = $this->PaymentPlanPrice->find('first', array(
22069                        'fields' => array(
22070                            'amount',
22071                            'start_date'
22072                        ),
22073                        'conditions' => array('id' => $userData['price_id'])
22074                    ));
22075
22076                    // if empty
22077                    if (!$data) {
22078                        $this->log(__METHOD__. ' Payment plan price data does not exist. --> ' . json_encode($userData) . ' price id --> ' , json_encode($priceId), $logFileName);
22079                        return $result;
22080                    }
22081
22082                    $amount = $data['PaymentPlanPrice']['amount'];
22083                    $priceId = $userData['price_id'];
22084                    $planStartDate = $data['PaymentPlanPrice']['start_date'];
22085                }
22086            }
22087
22088            $_forcePlanID = Configure::read('payment_plans.premium_plan');
22089
22090            // - change plan to lite if already lite plan user 
22091            if ($isLitePlanUser) {
22092                $_forcePlanID = Configure::read('payment_plans.light_plan');
22093            }
22094
22095            // - change plan to chocotto if already chocotto plan user 
22096            if ($isChocottoPlanUser) {
22097                $_forcePlanID = Configure::read('payment_plans.chocotto_plan');
22098            }
22099
22100            // get force payment plan data
22101            $fuData = $this->PaymentPlanPrice->getPaymentData(array(
22102                'currencyCode' => $currencyCode,
22103                'paymentPlanId' => $_forcePlanID,
22104                'forceUpdate' => true,
22105                'logFileName' => $logFileName
22106            ));
22107
22108            // if force update
22109            if (
22110                isset($fuData['planStartDate'])
22111                && $fuData['planStartDate'] > $planStartDate
22112                && $fuData['priceId'] != $priceId
22113                && myTools::forceUpdateIncludeFreeTrial($paymentPlanId)
22114            ) {
22115                $result = $fuData;
22116            } else {
22117                $result = array(
22118                    'amount' => $amount,
22119                    'fAmount' => myTools::formatAmount($amount),
22120                    'priceId' => $priceId,
22121                    'paymentPlanId' => $_forcePlanID
22122                );
22123            }
22124        }
22125
22126        return $result;
22127    }
22128
22129    private function changePaymentPlanIfTelecomUser($user = array()) {
22130        if (isset($user['card_company']) && $user['card_company'] == Configure::read('card_company.telecom')) {
22131            // get zeus latest premium payment plan data
22132            $premiumPlan = $this->PaymentPlanPrice->getPaymentData(array(
22133                'currencyCode' => Configure::read('currency_jpy'),
22134                'paymentPlanId' => Configure::read('payment_plans.premium_plan')
22135            ));
22136
22137            if (!$premiumPlan) {
22138                return $user;
22139            }
22140
22141            // change user payment plan
22142            $user['payment_plan_id'] = $premiumPlan['paymentPlanId'];
22143            $user['price_id'] = $premiumPlan['priceId'];
22144        }
22145
22146        return $user;
22147    }
22148    /**
22149     * @api {get} /mobapp/notice/coupon_code_plan/:token notice_coupon_code_plan()
22150     * @apiName notice_coupon_code_plan
22151     * @apiGroup Payment
22152     * @apiDescription This endpoint is used to display the notice page for the coupon code plan.
22153     * 
22154     * @apiParam {String} token User token
22155     * 
22156     * @apiSuccess {View} Render Display the notice page for the coupon code plan.
22157     * 
22158     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage.
22159     * 
22160     * @apiSuccessExample Success Response:
22161     * Display the notice page for the coupon code plan.
22162     * 
22163     * @apiErrorExample Error Response:
22164     * Redirects to {{ENV}}/mobapp/retrypage.
22165     * 
22166     * @apiSampleRequest off
22167     */
22168    public function notice_coupon_code_plan() {
22169        $this->layout = 'mobapp';
22170        $this->set('title_for_layout', __('無料キャンペーン|オンライン英会話のネイティブキャンプ'));
22171        $this->complimentaryPlanValidation();
22172        $this->render(myTools::getDeviceUrl() . 'Static/notice_plan-coupon_code');
22173    }
22174    /**
22175     * @api {get} /mobapp/notice/coupon_code_plan_change/:token notice_coupon_code_plan_change()
22176     * @apiName notice_coupon_code_plan_change
22177     * @apiGroup Payment
22178     * @apiDescription This endpoint is used to display the notice page for the coupon code plan change.
22179     * 
22180     * @apiParam {String} token User token
22181     * 
22182     * @apiSuccess {View} Render Display the notice page for the coupon code plan change.
22183     * 
22184     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage.
22185     * 
22186     * @apiSuccessExample Success Response:
22187     * Display the notice page for the coupon code plan change.
22188     * 
22189     * @apiErrorExample Error Response:
22190     * Redirects to {{ENV}}/mobapp/retrypage.
22191     * 
22192     * @apiSampleRequest off
22193     */
22194    public function notice_coupon_code_plan_change() {
22195        $this->layout = 'mobapp';
22196        $user = $this->complimentaryPlanValidation();
22197        if ($user['card_company'] == Configure::read('card_company.zeus')) {
22198            $urlExtension = 'credit_charge';
22199        } else {
22200            $urlExtension = 'wp_credit_charge';
22201        }
22202
22203        $this->set('urlExtension', $urlExtension);
22204
22205        // - NJ-23812 : add redirection to the page
22206        $rediUrl = myTools::getUrl() . '/mobapp/payment/'.$urlExtension.myTools::getMobappToken($_GET);
22207        $this->redirect($rediUrl);
22208
22209        $this->render(myTools::getDeviceUrl() . 'Static/notice_coupon_code_plan_change');
22210    }
22211
22212    private function complimentaryPlanValidation() {
22213        $urlParams = myTools::getMobappToken($_GET);
22214        // if token is not set
22215        if (!$this->request->query['token']) {
22216            $this->log(__METHOD__.' token does not exist.', 'debug');
22217            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
22218        }
22219
22220        $token = $this->request->query['token'];
22221        $uData = $this->User->find('first', array(
22222            'fields' => array(
22223                'complimentary_code',
22224                'card_company'
22225            ),
22226            'conditions' => array('api_token' => $token),
22227            'recursive' => -1
22228        ));
22229
22230        if (!$uData) {
22231            $this->log(__METHOD__.' user does not exist.' . json_encode($token), 'debug');
22232            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
22233        }
22234
22235        // if not complimentary plan
22236        if (!isset($uData['User']['complimentary_code'])) {
22237            $this->log(__METHOD__.' user is not a complimentary plan.' . json_encode($token), 'debug');
22238            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
22239        }
22240
22241        // check if card company is not zeus or worldpay
22242        if (!in_array($uData['User']['card_company'], array(Configure::read('card_company.zeus'), Configure::read('card_company.worldpay')))) {
22243            $this->log(__METHOD__.' invalid user card company.' . json_encode($token), 'debug');
22244            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
22245        }
22246
22247        $this->set('token', $token);
22248        return $uData['User'];
22249    }
22250
22251    // NC-6593
22252    private function updateUserCardCompanyToZeus($userId) {
22253        $cardCompany = Configure::read('card_company.zeus');
22254        $this->User->validate = array();
22255        $this->User->read(array('card_company'), $userId);
22256        # set card_company
22257        $this->User->set('card_company', $cardCompany);
22258        # update userid
22259        return ($this->User->save());
22260    }
22261
22262    //NJ-69126 : private to public for unit test purposes
22263    public function slackWPErrorPostMsg($paymentHash = '', $userId = '', $errMsg = '', $paymentStatus = '') {
22264        $mySlack = new mySlack();
22265        $mySlack->channel = myTools::checkChannel("#nc-wp-fail", "#fdc-test-channel");
22266        $mySlack->username = "WP ERROR REPORT";
22267        $mySlack->link_names = true;
22268        $mySlack->text = "```";
22269        $mySlack->text .= "payment_hash: {$paymentHash}\n\n";
22270        $mySlack->text .= "payment_status: {$paymentStatus}\n\n";
22271        $mySlack->text .= "user_id: {$userId}\n\n";
22272        $mySlack->text .= "error: {$errMsg}\n\n";
22273        $mySlack->text .= "```";
22274        $mySlack->sendSlack();
22275    }
22276
22277    /**
22278     * Check if complimentary user
22279     * @param array $user
22280     * @return boolean $comPlanUser
22281     */
22282    private function ifComPlanUser($user = array()) {
22283        $comPlanUser = false;
22284
22285        // if has complimentary code
22286        if (isset($user['complimentary_code']) && trim($user['complimentary_code']) != '') {
22287            // set com_plan_user to true if payment plan id is not null and is complimentary plan
22288            if (isset($user['payment_plan_id']) && $user['payment_plan_id'] == Configure::read('payment_plans.complimentary_plan')){
22289                $comPlanUser = true;
22290            // set com_plan_user to true if payment plan id is null and is complimentary plan
22291            } elseif (!isset($user['payment_plan_id']) && $this->Payment->ifComPlanUser($user['id'])) {
22292                $comPlanUser = true;
22293            }
22294        }
22295
22296        return $comPlanUser;
22297    }
22298
22299    private function getCorporatePaymentPlan($userData = array(),$params = array()) {
22300        $planData = array();
22301        $corporateType = myTools::getCoporateTypeUsingPaymentPlanId($userData['payment_plan_id']);
22302        $corporateIndiUser = false;
22303
22304        // get corporate admin payment method
22305        $corporateAdminData = $this->Corporate->find('first', array(
22306            'fields' => array('payment_method'),
22307            'conditions' => array(
22308                'id' => $userData['corporate_id'],
22309                'status' => 1
22310            ),
22311            'recursive' => -1
22312        ));
22313
22314        if (!$corporateAdminData) {
22315            return $planData;
22316        }
22317
22318        // set corporate admin payment method;
22319        $caPaymentMethod = $corporateAdminData['Corporate']['payment_method'];
22320
22321        $ppIdParams = array(
22322            'corporateType' => isset($corporateType) ? $corporateType : $params['corporate_type'],
22323            'paymentMethod' => $caPaymentMethod
22324        );
22325
22326        $paymentPlanId = $this->PaymentPlanPrice->getCorporateUserPaymentPlanId($ppIdParams);
22327
22328        if(
22329            empty($paymentPlanId) && // payment planid empty
22330            (!isset($params['corporate_type']) || !$params['corporate_type']) && // no corporate type data
22331            $caPaymentMethod == 1 // // individual
22332        ) {
22333            $paymentPlanId = $this->getDefaultPlanId($userData['corporate_id']);
22334        }
22335
22336        if (!isset($paymentPlanId)) {
22337            return $planData;
22338        }
22339
22340        // get corporate plan data
22341        $planData = $this->PaymentPlanPrice->getPaymentData(array(
22342            'currencyCode' => $userData['currency_code'],
22343            'paymentPlanId' => $paymentPlanId,
22344            'logFileName' => 'card_charge'
22345        ));
22346
22347        if ($planData) {
22348            $planData['corporateIndiUser'] = $caPaymentMethod == 1 ? true : false;
22349        }
22350
22351        return $planData;
22352    }
22353    /**
22354     * @api {post} /mobapp/corporate_register_card/:token mobapp_corporate_register_card()
22355     * @apiName mobapp_corporate_register_card
22356     * @apiGroup Payment
22357     * @apiDescription This endpoint is used to register a corporate user's credit card.
22358     * 
22359     * @apiParam {String} token The user's token
22360     * 
22361     * @apiBody {Number} cardnumber The credit card number
22362     * @apiBody {Number} expyy The credit card expiration year
22363     * @apiBody {Number} expmm The credit card expiration month
22364     * @apiBody {String} username The credit card holder's name
22365     * @apiBody {String} zeusTokenValue The zeus token value
22366     * 
22367     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/close?token={{token}}&corporate_register_card=1 if successful.
22368     * 
22369     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage{{urlParams}} if the token is missing / if user does not exist or not a corporate user.
22370     * 
22371     * @apiExample Example usage:
22372     * {
22373     *         "cardnumber": 4444333322221111,
22374     *         "expyy": 2028,
22375     *         "expmm": 12,
22376     *         "username": "John Doe",
22377     *         "zeusTokenValue": "zeusTokenValue"
22378     * }
22379     * 
22380     * @apiSuccessExample Success Response:
22381     * Redirects to {{ENV}}/mobapp/close?token={{token}}&corporate_register_card=1
22382     * 
22383     * @apiErrorExample Error Response:
22384     * Redirects to {{ENV}}/mobapp/retrypage{{urlParams}}
22385     * 
22386     * @apiSampleRequest off
22387     */
22388    public function mobapp_corporate_register_card() {
22389        $this->layout = "mobapp";
22390        $urlParams = myTools::getMobappToken($_GET);
22391
22392        // redirect to retry page if parameter token does not exist
22393        if (!isset($this->request->query['token'])) {
22394            $this->log(__METHOD__ . ' missing parameter token. --> ' . json_encode($urlParams), 'debug');
22395            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
22396        }
22397
22398        $apiToken = $this->request->query['token'];
22399        $conditions = array(
22400            'api_token' => $apiToken,
22401            'corporate_id IS NOT NULL',
22402            'payment_plan_id IS NOT NULL',
22403            // 'card_company IS NULL',
22404            // 'card_brand IS NULL',
22405            // 'card_number IS NULL'
22406        );
22407
22408        // get user data
22409        $userData = $this->User->getUserData($conditions, array('*'), 'first');
22410        $userObj = new UserTable($userData['User']);
22411        $fromPage = 'reservation';
22412        if (
22413            !empty($userData['User']['corporate_id']) && 
22414            in_array($userObj->getMembershipTypeIndex(), Configure::read('common_corporate_payment_memberships'))
22415        ) {
22416            return $this->redirect(myTools::getUrl() . '/mobapp/common_corporate_payment?type='. Configure::read('payment_url_type.corporate_type.corporate_register_card') .'&token=' . $apiToken . '&from_page=' . $fromPage);
22417        }
22418
22419        // redirect to retry page if does not exist or exist but not corporate user
22420        if (!$userData) {
22421            $this->log(__METHOD__ . ' user doest not exist or exist but not a corporate users. --> ' . json_encode($urlParams), 'debug');
22422            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
22423        }
22424
22425        $registerCardError = false;
22426        if ($this->request->is('post')) {
22427            $postData = $this->request->data;
22428            $this->set('data', $postData);
22429            $userData = $userData['User'];
22430
22431            // get form information
22432            $data = $postData['ZPaymentFullLogs'];
22433            //- set user id
22434            $userId = $userData['id'];
22435            //- default amount
22436            $paymentAmount = 0;
22437
22438            // get receivable reservation payment
22439            $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userId);
22440            if ($receivablePayment) {
22441                $paymentAmount += $receivablePayment;
22442            }
22443
22444            // get appreciation receivable payments
22445            $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('appreciation_data.payment_element_type'));
22446            if ($appreciationReceivable) {
22447                $paymentAmount += $appreciationReceivable;
22448            }    
22449
22450            // set payment params
22451            $paymentParams = array(
22452                'currencyCode' => $userData['currency_code'],
22453                'paymentPlanId' => $userData['payment_plan_id'],
22454                'priceId' => $userData['price_id'],
22455                'remoteAddress' => $_SERVER["REMOTE_ADDR"],
22456                'formType' => Configure::read('corporate_credit_card_registration'),
22457                'paymentType' => Configure::read('payment_types.payment_plan'),
22458                'paymentAmount' => $paymentAmount,
22459                'logFileName' => 'corporate_credit_card_registration',
22460                'corporateSettlementType' => Configure::read('corporate_settlement_types.corporate_card_registration')
22461            );
22462
22463            // card expiration date
22464            if (isset($data['expyy']) && isset($data['expmm'])) {
22465                $paymentParams['cardExpirationDate'] = array('cardExpirationDate' => date('Y-m-t', strtotime($data['expyy'] . '-' . $data['expmm'])));
22466            }
22467
22468            $ptParams = array(
22469                'user_id' => $userId,
22470                'payment_hash' => myTools::generateOrderCode($userId),
22471                'payment_params' => json_encode($paymentParams),
22472                'course_id' => Configure::read("credit.course_id")
22473            );
22474
22475            if ($pt = $this->PaymentTransaction->setWPPaymentTransaction($ptParams)) {
22476
22477                $zeuspayData = array(
22478                    'clientIp' => Configure::read('ZEUS_clientip'), # clientip, # clientip
22479                    'cardNumber' => isset($data['cardnumber']) ? (int) $data['cardnumber'] : null,
22480                    'expyy' => isset($data['expyy']) ? (int) $data['expyy'] : null,
22481                    'expmm' => isset($data['expmm']) ? (int) $data['expmm'] : null,
22482                    'telNo' => Configure::read('credit.default_telno'), # telephone number
22483                    'email' => $userData['email'], # email
22484                    'username' => mb_strtoupper($data['username']), # username
22485                    'sendId' => $userId, # id
22486                    'money' => $paymentAmount, # money
22487                    'tokenKey' => $data['zeusTokenValue'],
22488                    'paymentHash' => $pt['payment_hash']
22489                );
22490
22491                // send curl request
22492                $paymentResponse =$this->ZCharge->charge_regist(json_encode($zeuspayData));
22493
22494                if ($paymentResponse[0] == "Success_order" || $paymentResponse == "Success_order") {
22495                    return $this->redirect(myTools::getUrl() . '/mobapp/close?token=' . $apiToken . '&corporate_register_card=1');
22496                }
22497            }
22498
22499            $registerCardError = true;
22500        }
22501
22502        $this->set('title_for_layout', '新規会員登録|オンライン英会話のネイティブキャンプ');
22503        $this->set('zeusTransactionFlag', true);
22504        $this->set('registerCardError', $registerCardError);
22505        $this->set('amount', $paymentAmount);
22506        $this->set('paymentHash', $pt['payment_hash']);
22507        $this->render(myTools::getDeviceUrl() . 'Payment/corporate_register_form');
22508    }
22509
22510    // NJ-69193 ~ private to public to easily access via unit test
22511    public function slackZeusErrorPostMsg($type = '', $line = '', $method = '', $userId = '', $failMessage='', $debugData = array(), $moreDebugData = array()) {
22512        $mySlack = new mySlack();
22513        $mySlack->channel = myTools::checkChannel("#nc-settlement", "#nc-settlement-dev");
22514        $mySlack->username = "NC Payment Failed";
22515        $mySlack->text = "```";
22516        $mySlack->text .= "ROLLBACK TYPE:\n";
22517        $mySlack->text .= $type . "\n\n";
22518        $mySlack->text .= "LINE NUMBER:\n";
22519        $mySlack->text .= $line . "\n\n";
22520        $mySlack->text .= "METHOD:\n";
22521        $mySlack->text .= $method . "\n\n";
22522        $mySlack->text .= "USER ID:\n";
22523        $mySlack->text .= $userId . "\n\n";
22524        $mySlack->text .= "KICKBACK URL:\n";
22525        $mySlack->text .= $_SERVER['REQUEST_URI'] . "\n\n";
22526        $mySlack->text .= "EC2 INSTANCE ID:\n";
22527        $mySlack->text .= exec('ec2-metadata -i') . "\n\n";
22528        $mySlack->text .= "REASON OF FAILURE:\n";
22529        $mySlack->text .= date("Y-m-d H:i:s") . " " . $failMessage."\n";
22530        $mySlack->text .= json_encode($debugData);
22531        if (!empty($moreDebugData)) {
22532            $mySlack->text .= "\n" . json_encode($moreDebugData);
22533        }
22534        $mySlack->text .= "```";
22535        $mySlack->sendSlack();
22536    }
22537
22538    private function processPayPalPayment($data = array(), $userData = array()) {
22539        $logFileName = 'paypal_debug';
22540
22541        $memKey = 'paypalBillingAgreementData_' . $userData['api_token'];
22542        // return false if memcache billing agreement data does not exist
22543        if (!$paypalData = $this->memcache->get($memKey)) {
22544            $this->log(__METHOD__ . ' Memcached billing agreement data does not exist. --> ' . json_encode($paypalData) . ' | data --> ' . json_encode($data) . ' | user data --> ' . json_encode($userData), $logFileName);
22545            return false;
22546        }
22547
22548        if (
22549            !isset($paypalData['accessTokenData']['access_token']) || 
22550            !isset($paypalData['finalizeBillingAgreementData']['id']) ||
22551            !isset($paypalData['finalizeBillingAgreementData']['payer']['payer_info']['payer_id'])
22552        ) {
22553            $this->log(__METHOD__ . ' Missing billing agreement param(s). --> ' . json_encode($paypalData), $logFileName);
22554            return false;
22555        }
22556
22557        $accessToken = $paypalData['accessTokenData']['access_token'];
22558        $baId = $paypalData['finalizeBillingAgreementData']['id']; // billing agreement id
22559        $payerId = $paypalData['finalizeBillingAgreementData']['payer']['payer_info']['payer_id'];
22560        $payerEmail = $paypalData['finalizeBillingAgreementData']['payer']['payer_info']['email'];
22561        $formType = $data['formType'];
22562        $monthlyPayment = 0;
22563        if(isset($data['ZPaymentFullLogs']['money'])){
22564            $monthlyPayment = $data['ZPaymentFullLogs']['money'];
22565        }else if(isset($data['paymentPlanData']['amount'])){
22566            $monthlyPayment = $data['paymentPlanData']['amount'];
22567        }
22568        $discountedAmount = 0;
22569
22570        // if using coupon
22571        if (isset($data['monthlyDiscount']) && $formType == Configure::read('payment_credit_retry')) {
22572            $discountedAmount = $userData['discounted_amount'] = $data['monthlyDiscount'];
22573            $userData['monthlyDiscount'] = $data['monthlyDiscount'];
22574            $userData['monthly_grp_id'] = isset($data['monthly_grp_id']) ? $data['monthly_grp_id'] : 0;
22575            $monthlyPayment -= $data['monthlyDiscount'];
22576        }
22577
22578        // if using coupon during force settlement
22579        if (!empty($data['couponUseSettlement']['useCouponAmount']) && in_array($formType, Configure::read('allow_coupon.settlement_form_type'))) {
22580            $discountedAmount += $data['couponUseSettlement']['useCouponAmount'];
22581            $userData['couponUseSettlement'] = $data['couponUseSettlement'];
22582            $monthlyPayment -= $data['couponUseSettlement']['useCouponAmount'];
22583        }
22584
22585        // If retry and has annual discount
22586        if ($formType == Configure::read('payment_credit_retry') || $formType == Configure::read('payment_credit_force_charge')) {
22587            // get user active annual discount option
22588            $annualDiscountOptionData = $this->UserDiscountOptionsTerm->getTerm([
22589                'user_id' => $userData['id'],
22590                'discount_option_id' => Configure::read('discount_option.annual.plan_id'),
22591                'status' => 1
22592            ]);
22593
22594            if ($annualDiscountOptionData) {
22595                unset($annualDiscountOptionData['contract_start']);
22596                $annualDiscountOptionData += [
22597                    'dosh_event' => Configure::read('discount_option.dosh_event.annual_discount'),
22598                    'dosh_status' => Configure::read('discount_option.dosh_status.monthly_discount')
22599                ];
22600                $data['discountOption'] = $annualDiscountOptionData;
22601            }
22602        }
22603
22604        $receivablePayment = $data['receivablePayment'];
22605        $appreciationReceivable = $data['appreciationReceivable'];
22606        $liveLessonReceivable = $data['liveLessonReceivable'];
22607        $totalAmount =  $monthlyPayment + $receivablePayment + $appreciationReceivable + $liveLessonReceivable;
22608
22609        // if has discount option
22610        if (isset($data['discountOption'])) {
22611            $totalAmount -= $data['discountOption']['amount'];
22612            $userData['discountOption'] = $data['discountOption'];
22613            $monthlyPayment -= $data['discountOption']['amount'];
22614        }
22615
22616        $userData['payment_plan_id'] = $paymentPlanId = $data['paymentPlanData']['paymentPlanId'];
22617        $userData['price_id'] = $priceId = $data['paymentPlanData']['priceId'];
22618        $userData['paymentAmount'] = $totalAmount;
22619
22620        // return false if failed to create payment transaction
22621        if (!$pt = $this->createPaymentTransaction($formType, $userData)) {
22622            $this->log(__METHOD__ .' Failed to create payment transaction. Params --> ' . json_encode($userData), $logFileName);
22623            return false;
22624        }
22625
22626        $paymentHash = $pt['payment_hash'];
22627        $ptPassword = $pt['password'];
22628        $ptPaymentParams = json_decode($pt['payment_params'], true);
22629        $platform = isset($ptPaymentParams['platform']) ? $ptPaymentParams['platform'] : null;
22630        $ptId = $pt['id'];
22631        $userId = $userData['id'];
22632        $cardCompany = Configure::read('card_company.paypal');
22633        $currencyId = Configure::read('default.settlement_currency_id');  // set currency id to jpy
22634        $currencyCode = Configure::read('default.user_currency');
22635        $paymentType = Configure::read('payment_types.payment_plan');
22636        $dateNow = date('Y-m-d H:i:s');
22637        $ftForceCharge = Configure::read('payment_credit_force_charge');
22638        $ftRetry = Configure::read('payment_credit_retry');
22639        $ftCardAuth = Configure::read('payment_credit_authentication');
22640        $membershipStatusIndex = UserTable::getStudentMembershipStatus($userId);
22641        $currency_before = $currencyCode;
22642        $plan_before = $paymentPlanId;
22643        $appreciationFlg = 0;
22644        $tipAmount = null;
22645
22646        $ftLitePlanPaid = Configure::read('payment_lite_credit_paid');
22647        $isLitePlanUser = in_array($paymentPlanId, Configure::read('lite_payment_plans')) ? true : false;
22648
22649        //- NJ-27262 chocotto plans
22650        $ftChocottoPlanFree = Configure::read('payment_credit_chocotto_free');
22651        $ftChocottoPlanPaid = Configure::read('payment_credit_chocotto_monthly_payment');
22652        $ftChocottoPlanRetry = Configure::read('payment_credit_chocotto_retry');
22653        $ftChocottoPlanForceCharge = Configure::read('payment_credit_chocotto_force_charge');
22654
22655        $isChocottoPlanUser = in_array(
22656            $paymentPlanId,
22657            [
22658                Configure::read('payment_plans.free_trial_chocotto'),
22659                Configure::read('payment_plans.chocotto_plan')
22660            ]
22661        );
22662
22663        // load PayPal class
22664        if (!class_exists('PayPal')) {
22665            App::import('Lib', 'PayPal');
22666        }
22667
22668        $paypal = new PayPal();
22669
22670        $createOrderParams = array(
22671            'accessToken' => $accessToken,
22672            'paypalRequestId' => $ptId,
22673            'intent' => 'CAPTURE',
22674            'paymentHash' => $paymentHash,
22675            'userId' => $userId,
22676            'currencyCode' => $currencyCode,
22677            'amount' => (int)$totalAmount,
22678            'billingAgreementId' => $baId
22679        );
22680
22681        // create order
22682        $createOrderResult = $paypal->createOrder($createOrderParams);
22683        $paypalData['create_order_data'] = $createOrderResult;
22684
22685        // save settlement history for tracking
22686        if (!SettlementHistoryTable::add(array(
22687                'userId' => $userId,
22688                'params' => json_encode($paypalData),
22689                'createdIp' => $dateNow,
22690                'modifiedIp' => $dateNow
22691            )
22692        )) {
22693            $this->log(__METHOD__ . ' Failed to save paypal result data in settlement history. ' . json_encode($paypalData), $logFileName);
22694            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save paypal result data in settlement history', $paypalData);
22695            return false;
22696        }
22697
22698        // If retry payment and zero payment
22699        if (
22700            in_array(
22701                $formType, 
22702                [
22703                    Configure::read('payment_credit_retry'),
22704                    Configure::read('payment_credit_chocotto_retry')
22705                ]
22706            ) && 
22707            $totalAmount <= 0
22708        ) {
22709            $zeroPaymentParams = array(
22710                'paymentHash' => $paymentHash,
22711                'userId' => $userId,
22712                'money' => $totalAmount,
22713                'cardCompany' => $cardCompany,
22714                'controllerName' => 'Payment',
22715                'actionName' => 'processPayPalPayment',
22716                'logFileName' => 'card_retry'
22717            );
22718            if (!$this->Payment->zeroPayment($zeroPaymentParams)) {
22719                $this->log(__METHOD__ . ' Failed to save payment data. ' . json_encode($zeroPaymentParams) . ' -- ' . json_encode($data), $logFileName);
22720                return false;
22721            }
22722
22723            // Check if has annual discount then insert monthly discount option after 0 payment
22724            if (isset($data['discountOption'])) {
22725                $discountOption = isset($data['discountOption']) ? $data['discountOption'] : [];
22726        
22727                $discountOption += [
22728                    'contract_start' => $contractStart,
22729                    'currency_code' => $currencyCode,
22730                    'payment_id' => $this->Payment->id,
22731                    'dosh_settlement_status' => 1, // success
22732                    'form_type' => $formType
22733                ];
22734
22735                if (!$this->UserDiscountOptionsTerm->processMonthlyDiscountOption($discountOption)) {
22736                    $this->log(__METHOD__ . ' Failed to process monthly discount option. ' . json_encode($discountOption), $logFileName);
22737                    return false;
22738                }
22739            }
22740
22741            return true;
22742        }
22743
22744        if (isset($createOrderResult['status']) && $createOrderResult['status'] === 'COMPLETED') {
22745            $paymentData = array(
22746                'user_id' => $userId,
22747                'amount' => $monthlyPayment,
22748                'status' => 1,
22749                'reference_id' => $userId,
22750                'payment_transaction_password' => $ptPassword,
22751                'card_company' => $cardCompany,
22752                'param1' => json_encode($paypalData),
22753                'form_type' => $formType,
22754                'ordd' => $paymentHash,
22755                'transaction_code' => $paymentHash,
22756                'currency_id' => $currencyId,
22757                'currency_code' => $currencyCode,
22758                'payment_id' => $paymentPlanId,
22759                'price_id' => $priceId,
22760                'payment_type' => $paymentType,
22761                'discounted_amount' => $discountedAmount
22762            );
22763
22764            $forceSettlementWithCoupon = false;
22765            // NJ-47740 - set used coupon
22766            if (
22767                !empty($data['couponUseSettlement']) && 
22768                !empty($data['couponUseSettlement']['useCouponAmount']) && 
22769                in_array($formType, Configure::read('allow_coupon.settlement_form_type'))
22770            ) {
22771                $couponData = $data['couponUseSettlement'];
22772                $couponData['nextChargeDate'] = date('Y-m-d');
22773                $couponData['request_result'] = true;
22774                
22775                $result_coupon_use = $this->UsersCouponV1->performCouponUse($couponData);
22776                $result_coupon_use = !empty($result_coupon_use) ? json_decode($result_coupon_use,true) : array();
22777                
22778                if (isset($result_coupon_use['cgrp_id'])) {
22779                    $paymentData['discounted_amount'] = $data['couponUseSettlement']['useCouponAmount'];
22780                    $paymentData['coupon_request_id'] = $result_coupon_use['cgrp_id'];
22781                    $forceSettlementWithCoupon = true;
22782                }
22783            } else if (isset($userData['monthly_grp_id'])) {
22784                $paymentData['coupon_request_id'] = $userData['monthly_grp_id'];
22785            }
22786            // NJ-47740 end
22787            
22788            $discountOption = isset($ptPaymentParams['discountOption']) ? $ptPaymentParams['discountOption'] : [];
22789    
22790            if (!empty($discountOption)) {
22791                $paymentData['discount_option_price_id'] = $discountOption['discount_option_price_id'];
22792            }
22793
22794            // create new payment
22795            $this->Payment->clear();
22796            $this->Payment->create();
22797            $this->Payment->set($paymentData);
22798            $this->Payment->validate = array();
22799
22800            // check if payment was not saved
22801            if (!$this->Payment->save()) {
22802                $this->log(__METHOD__ . ' Failed to save payment data. ' . json_encode($paymentData) . ' -- ' . json_encode($data), $logFileName);
22803                
22804                if ($forceSettlementWithCoupon) {
22805                    $couponUnconfirmData = array(
22806                        'grpId' => $paymentData['coupon_request_id'],
22807                        'userId' => $userId,
22808                        'kbn' => Configure::read('coupon_kbn.monthly_settlement')
22809                    );
22810                    
22811                    $res_unconfirm = $this->UsersCouponV1->performCouponUnconfirm($couponUnconfirmData);
22812                    
22813                    if (empty($res_unconfirm)) {
22814                        $this->log(__METHOD__ . ' failed to perform coupon unconfirm data. '. json_encode($couponUnconfirmData), $logFileName);
22815                    }
22816                }
22817                return false;
22818            }
22819
22820            $paymentId = $this->Payment->id;
22821            
22822            // NJ-47740
22823            if (!empty($paymentData['coupon_request_id']) && $paymentData['discounted_amount'] > 0) {
22824                // confirm coupon use request for discount
22825                $requestCouponConfirmData = array(
22826                    'grpId' => $paymentData['coupon_request_id'],
22827                    'paymentId' => $paymentId
22828                );
22829                $result_confirm = $this->UsersCouponV1->performCouponConfirm($requestCouponConfirmData);
22830                
22831                if (!$result_confirm) {
22832                    $this->log(__METHOD__ . ' Failed to confirm coupon use request. ' . json_encode($requestCouponConfirmData) . ' -- ' . json_encode($data), $logFileName);
22833                }
22834            }
22835            // NJ-47740 end
22836
22837            // update payment details
22838            $updatePaymentDetailParams = array(
22839                'currencyCode' => $paymentData['currency_code'],
22840                'formType' => $paymentData['form_type'],
22841                'paymentType' => $paymentData['payment_type'],
22842                'amount' => $paymentData['amount'],
22843                'discounted_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0,
22844                'familyId' => $userData['parent_id'],
22845                'cronDateRun' => $dateNow,
22846                'priceId' => $paymentData['price_id'],
22847                'paymentPlanId' => $paymentData['payment_id'],
22848                'user_id' => $paymentData['user_id'],
22849                'coupon_use_request_id' => isset($paymentData['coupon_request_id']) ? $paymentData['coupon_request_id'] : null,
22850                'coupon_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0
22851            );
22852
22853            if (!empty($discountOption)) {
22854                $updatePaymentDetailParams['discount_option_price_id'] = $discountOption['discount_option_price_id'];
22855                $updatePaymentDetailParams['discount_option_amount'] = $discountOption['amount'];
22856            }
22857
22858            $updatePaymentDetail = array(
22859                'id' => $ptId,
22860                'fields' => array(
22861                    'payment_details' => $updatePaymentDetailParams
22862                )
22863            );
22864
22865            if (!$this->PaymentTransaction->updateWPPaymentTransaction($updatePaymentDetail)) {
22866                $this->log(__METHOD__ . ' Failed to update payment details. ' . json_encode($updatePaymentDetail), $logFileName);
22867            }
22868            
22869            //update/add user`s settlement amount
22870            $this->User->updateUserPayments($paymentData);
22871
22872            // set transaction
22873            $dataSource = $this->User->getDataSource();
22874            $dataSource->begin();
22875
22876            // user array to be saved
22877            $saveUserArr = array(
22878                'status' => 1,
22879                'modified' => $dateNow,
22880                'fail_flg' => 0,
22881                'charge_flg' => 1,
22882                'counseling_attended_flg' => 0,
22883                'card_company' => $cardCompany,
22884                'hash16' => $userId,
22885                'last_charge_date' => $dateNow,
22886                'payment_plan_id' => $paymentPlanId,
22887                'price_id' => $priceId,
22888                'corporate_id' => null,
22889                'corporate_type' => null,
22890                'paypal_payer_id' => $payerId,
22891                'paypal_billing_agreement_id' => $baId,
22892                'card_expiration_date' => null,
22893                'paypal_payer_email' => $payerEmail
22894            );
22895
22896            if (in_array(
22897                $formType, 
22898                array(
22899                    $ftForceCharge,
22900                    $ftRetry,
22901                    $ftLitePlanPaid,
22902                    $ftChocottoPlanPaid,
22903                    $ftChocottoPlanRetry,
22904                    $ftChocottoPlanForceCharge
22905                )
22906            )) {
22907                // get and set next charge date
22908                $nextChargeDate = $this->User->getNextChargeDate();
22909                $saveUserArr['next_charge_date'] = $nextChargeDate;
22910                $saveUserArr['double_check_flg'] = 1;
22911                $saveUserArr['expired_card_flg'] = 0;
22912
22913                // give points to user join the campaign who retry payment
22914                if ($formType == $ftRetry) {
22915                    $this->loadModel("ContinuationCampaign");
22916                    $this->ContinuationCampaign->givePointsRetrySuccess(array('user_ids' => array($userId)));
22917                }
22918            } elseif ($formType == $ftCardAuth) {
22919                $saveUserArr['first_charge_date'] = $dateNow;
22920                $saveUserArr['platform'] = $platform;
22921
22922                // normal user
22923                $nextChargeDate = $this->User->getFirstNextChargeDate();
22924                $saveUserArr['next_charge_date'] = $nextChargeDate;
22925            }
22926            //NJ-7874 if appreciation flag and amount is set
22927            if (isset($ptPaymentParams['family_data']['applyPlan']['tip_max_amount']) && $ptPaymentParams['family_data']['applyPlan']['tip_max_amount']) {
22928                $tipAmount = $ptPaymentParams['family_data']['applyPlan']['tip_max_amount'];
22929            }
22930
22931            if (isset($ptPaymentParams['family_data']['applyPlan']['allow_appreciation_flg']) && $ptPaymentParams['family_data']['applyPlan']['allow_appreciation_flg'] && $tipAmount) {
22932                $appreciationFlg = 1;
22933            }
22934
22935            // NJ-1562 - appreciation on
22936            if( $paymentPlanId && in_array( $paymentPlanId, Configure::read('appreciation.payment_plan_id') ) ) {
22937                $saveUserArr['allow_appreciation_flg'] = 1; // on
22938
22939                //NJ-7874 Turn Off appreciation settings for Family Plan (Default)
22940                if (in_array($paymentPlanId, Configure::read('appreciation.can_coin_purchase_check')) ) {
22941                    $saveUserArr['allow_appreciation_flg'] = $appreciationFlg;
22942                    $saveUserArr['show_appreciation_flg'] = $appreciationFlg;
22943                    $saveUserArr['tip_max_amount'] = $tipAmount;
22944                } else {
22945                    //NJ-7548 : fetch the birthday and age
22946                    $userBirthday  = $userData['User']['birthday'] ?? $userData['birthday'];
22947                    $userAge = UserTable::getStudentAge($userBirthday);
22948                    $userAge = $userAge ? (int) $userAge : null;
22949
22950                    //show appreciation flg default
22951                    $showAppreciationFlg = 0;
22952
22953                    //change the show appreciation flg if no birthday set or 18 and above            
22954                    if (!$userAge || $userAge >= 18) {
22955                        $showAppreciationFlg = 1;
22956                    }
22957
22958                    $saveUserArr['show_appreciation_flg'] = $showAppreciationFlg;
22959                }
22960            }
22961
22962            // NC-7779 : check if user has chivox monthly test taken for the current month, and monthly_speaking_attended_flg ON,
22963            // turn Off the flag if users has not yet taken the exam for the current month.
22964            // @TODO check query
22965            if (
22966                isset($userData['monthly_speaking_attended_flg']) && isset($userData['monthly_speaking_business_attended_flg'])
22967                && ($userData['monthly_speaking_attended_flg'] == 1 || $userData['monthly_speaking_business_attended_flg'] == 1)
22968            ) {
22969                // check chivox monthly
22970                $paymentPlanIdsForChivoxMonthly = Configure::read('chivox.monthly.user_payment_plan_cantake_exam');
22971                if (in_array($paymentPlanId, $paymentPlanIdsForChivoxMonthly)) {
22972
22973                    // load model
22974                    $this->loadModel("UsersChivoxMonthlyTest");
22975
22976                    $userTestMonthFlag = $this->UsersChivoxMonthlyTest->checkUserCurrentMonthExam(array('user_id' => $userId));
22977                    $monthlySpeakingAttendedFlg = Configure::read('chivox.test_data_test_type.daily'); // test_type daily speaking 0
22978                    $monthlySpeakingBusinessAttendedFlg = Configure::read('chivox.test_data_test_type.business'); // test_type business 1
22979
22980                    // if user hat not yet taken the exam for current month
22981                    if (!in_array($monthlySpeakingAttendedFlg, $userTestMonthFlag)) {
22982                        $saveUserArr['monthly_speaking_attended_flg'] = 0;
22983                    }
22984                    if (!in_array($monthlySpeakingBusinessAttendedFlg, $userTestMonthFlag)) {
22985                        $saveUserArr['monthly_speaking_business_attended_flg'] = 0;
22986                    }
22987                }
22988            }
22989
22990            // update the user information
22991            $this->User->validate = array();
22992            if (!$read = $this->User->read(array_keys($saveUserArr), $userId)) {
22993                $this->log(__METHOD__ . ' User id does not exist. ' . json_encode($userData) . ' -- ' . json_encode($createOrderResult), $logFileName);
22994                $dataSource->rollback();
22995                return false;
22996            }
22997
22998            $this->User->set($saveUserArr);
22999            if (!$this->User->save()) {
23000                $this->log(__METHOD__ . ' Failed update user data. ' . json_encode($saveUserArr) . ' -- ' . json_encode($createOrderResult), $logFileName);
23001                $dataSource->rollback();
23002                return false;
23003            }
23004
23005            // check if membership status was change
23006            if (isset($ptPaymentParams['statusBefore']) && isset($ptPaymentParams['statusAfter']) && isset($ptPaymentParams['platform'])) {
23007                $currentUser = $this->User->find('first', array(
23008                    'fields' => array('User.parent_id', 'User.currency_code', 'User.payment_plan_id'),
23009                    'conditions' => array('User.id' => $userId),
23010                    'recursive' => -1
23011                ));
23012                $parentId = $currentUser['User']['parent_id'];
23013                $is_cron = 0;
23014                if (php_sapi_name() == 'cli'){
23015                    $is_cron = 1;
23016                } 
23017                   $currency_after = $currentUser['User']['currency_code'];
23018                   $plan_after = $currentUser['User']['payment_plan_id'];
23019
23020                $usclData = array(
23021                    'user_id' => $userId,
23022                    'platform' => $platform ?? '',
23023                    'card_company_before' => $userData['card_company'],
23024                    'status_before' => $ptPaymentParams['statusBefore'],
23025                    'status_after' => $ptPaymentParams['statusAfter'],
23026                    'controller_name' => $this->request->params['controller'],
23027                    'action_name' => $this->request->params['action'],
23028                    'parent_id' => $parentId,
23029                    'is_cron' => $is_cron,
23030                    'currency_before' => $currency_before,
23031                    'currency_after' => $currency_after,
23032                    'payment_plan_id_before' => $plan_before,
23033                    'payment_plan_id_after' => $plan_after,
23034                    'default_appreciation_flg' => $appreciationFlg,
23035                    'default_appreciation_amount' => $tipAmount
23036                );
23037                // save user change membership status
23038                if (!$this->UserStatusChangeLog->saveLog($usclData)) {
23039                    $dataSource->rollback();
23040                    return false;
23041                }
23042            }
23043
23044            // if has receivable payment
23045            if ($receivablePayment) {
23046                // set payment id
23047                $data["payment_id"] = $paymentId;
23048
23049                $paymentData = array(
23050                    'user_id' => $userId,
23051                    'amount' => $receivablePayment,
23052                    'status' => 1,
23053                    'type_id' => 1,
23054                    'reference_id' => $userId,
23055                    'card_company' => $cardCompany,
23056                    'param1' => json_encode($data),
23057                    'form_type' => Configure::read('payment_credit_receivable'),
23058                    'ordd' => $paymentHash,
23059                    'currency_code' => $currencyCode,
23060                    'transaction_code' => $paymentHash,
23061                    'price_id' => $priceId,
23062                    'payment_id' => $paymentPlanId,
23063                    'payment_type' => $paymentType,
23064                    'discounted_amount' => $discountedAmount
23065                );
23066
23067                // create new payment
23068                $this->Payment->clear();
23069                $this->Payment->create();
23070                $this->Payment->set($paymentData);
23071                $this->Payment->validate = array();
23072
23073                if (!$this->Payment->save()) {
23074                    $this->log(__METHOD__ . ' Failed to save payment data for receivable.' . json_encode($paymentData), $logFileName);
23075                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data for receivable.', $paymentData);
23076                    $dataSource->rollback();
23077                    return false;
23078                }
23079
23080                //update/add user`s settlement amount
23081                $this->User->updateUserPayments($paymentData);
23082                // set payment_id
23083                $receivablePaymentId = $this->Payment->id;
23084
23085                // set payment receivable statuses to 2 - received
23086                $this->PaymentReceivable->updateReceivableReservationPayment(
23087                    $userId,
23088                    array(
23089                        'status' => 2,
23090                        'payment_id' => $receivablePaymentId,
23091                        'payment_collection_date' => date("Y-m-d H:i:s"),
23092                        'card_company' => $cardCompany,
23093                        'payment_plan_id' => $paymentPlanId,
23094                        'membership_type_index' => $membershipStatusIndex
23095                    ),
23096                    array(
23097                        'PaymentReceivable.user_id' => $userId,
23098                        'PaymentReceivable.status' => 0,
23099                        'PaymentReceivable.payment_element_type' => 1,
23100                        'PaymentReceivable.created <=' => date("Y-m-d H:i:s")
23101                    )
23102                );
23103            }
23104
23105            // if has appreciation receivable payment
23106            if ($appreciationReceivable > 0) {
23107                // set payment id
23108                $data["payment_id"] = $paymentId;
23109                //reset payment data
23110                $paymentData = array();
23111
23112                // set variables
23113                $paymentData = array(
23114                    'user_id' => $userId,
23115                    'amount' => $appreciationReceivable,
23116                    'status' => 1,
23117                    'type_id' => 1,
23118                    'reference_id' => $userId,
23119                    'card_company' => $cardCompany,
23120                    'param1' => json_encode($data),
23121                    'form_type' => Configure::read('appreciation_data.payment_form_type'),
23122                    'ordd' => $paymentHash,
23123                    'currency_code' => $currencyCode,
23124                    'transaction_code' => $paymentHash,
23125                    'price_id' => $priceId,
23126                    'payment_id' => $paymentPlanId,
23127                    'payment_type' => $paymentType,
23128                    'discounted_amount' => $discountedAmount
23129                );
23130
23131                // create new payment
23132                $this->Payment->clear();
23133                $this->Payment->create();
23134                $this->Payment->set($paymentData);
23135                $this->Payment->validate = array();
23136
23137                if (!$this->Payment->save()) {
23138                    $this->log(__METHOD__ . ' Failed to save appreciation receivable payment data for receivable.' . json_encode($paymentData), $logFileName);
23139                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data for receivable.', $paymentData);
23140                    $dataSource->rollback();
23141                    return false;
23142                }
23143                //update/add user`s settlement amount
23144                $this->User->updateUserPayments($paymentData);
23145                // set payment_id
23146                $appreciationPaymentId = $this->Payment->id;
23147
23148                // set live lesson payment receivable statuses to 2 - received
23149                $this->PaymentReceivable->updateReceivableReservationPayment(
23150                    $userId,
23151                    array(
23152                        'status' => 2,
23153                        'payment_id' => $appreciationPaymentId,
23154                        'payment_collection_date' => date("Y-m-d H:i:s"),
23155                        'card_company' => $cardCompany,
23156                        'payment_plan_id' => $paymentPlanId,
23157                        'membership_type_index' => $membershipStatusIndex
23158                    ),
23159                    array(
23160                        'PaymentReceivable.user_id' => $userId,
23161                        'PaymentReceivable.status' => 0,
23162                        'PaymentReceivable.payment_element_type' => Configure::read('appreciation_data.payment_element_type'),
23163                        'PaymentReceivable.created <=' => date("Y-m-d H:i:s")
23164                    )
23165                );
23166            }
23167
23168            // if has live lesson receivable payment
23169            if ($liveLessonReceivable) {
23170                // set payment id
23171                $data["payment_id"] = $paymentId;
23172
23173                $paymentData = array(
23174                    'user_id' => $userId,
23175                    'amount' => $liveLessonReceivable,
23176                    'status' => 1,
23177                    'type_id' => 1,
23178                    'reference_id' => $userId,
23179                    'card_company' => $cardCompany,
23180                    'param1' => json_encode($data),
23181                    'form_type' => Configure::read('payment_live_lesson_receivable'),
23182                    'ordd' => $paymentHash,
23183                    'currency_code' => $currencyCode,
23184                    'transaction_code' => $paymentHash,
23185                    'price_id' => $priceId,
23186                    'payment_id' => $paymentPlanId,
23187                    'payment_type' => $paymentType,
23188                    'discounted_amount' => $discountedAmount
23189                );
23190
23191                // create new payment
23192                $this->Payment->clear();
23193                $this->Payment->create();
23194                $this->Payment->set($paymentData);
23195                $this->Payment->validate = array();
23196
23197                if (!$this->Payment->save()) {
23198                    $this->log(__METHOD__ . ' Failed to save payment data for receivable.' . json_encode($paymentData), $logFileName);
23199                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data for receivable.', $paymentData);
23200                    $dataSource->rollback();
23201                    return false;
23202                }
23203
23204                //update/add user`s settlement amount
23205                $this->User->updateUserPayments($paymentData);
23206                // set payment_id
23207                $liveLessonPaymentId = $this->Payment->id;
23208
23209                // set live lesson payment receivable statuses to 2 - received
23210                $this->PaymentReceivable->updateReceivableReservationPayment(
23211                    $userId,
23212                    array(
23213                        'status' => 2,
23214                        'payment_id' => $liveLessonPaymentId,
23215                        'payment_collection_date' => date("Y-m-d H:i:s"),
23216                        'card_company' => $cardCompany,
23217                        'payment_plan_id' => $paymentPlanId,
23218                        'membership_type_index' => $membershipStatusIndex
23219                    ),
23220                    array(
23221                        'PaymentReceivable.user_id' => $userId,
23222                        'PaymentReceivable.status' => 0,
23223                        'PaymentReceivable.payment_element_type' => Configure::read('payment_element_type.live'),
23224                        'PaymentReceivable.created <=' => date("Y-m-d H:i:s")
23225                    )
23226                );
23227            }            
23228
23229            // NC-7029: CHECK REFERRAL USER
23230            if ($formType == Configure::read('payment_credit_retry') && isset($data['discountedAmount'])) {
23231                $ruData = array(
23232                    'referee_id' => $userId,
23233                    'payment_plan_id' => $paymentPlanId,
23234                    'currency_code' => $currencyCode,
23235                    'logFileName' => $logFileName,
23236                    'form_type' => $formType
23237                );
23238
23239                $couponReferredData = $this->UsersReferral->checkReferredUser($ruData);
23240                if (isset($couponReferredData['error']) && $couponReferredData['error']) {
23241                    $this->log(__METHOD__ . ' Failed to update users referral event flg.' . json_encode($ruData), $logFileName);
23242                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update users referral event flg.', $ruData);
23243                    $dataSource->rollback();
23244                    return false;
23245                }
23246
23247
23248                $couponMailId = Configure::read('site_in_mail.coupon_mail_template_id');
23249
23250                // send coupon mail to referee
23251                if (isset($couponReferredData['sendMailToReferee']) && $couponReferredData['sendMailToReferee']) {
23252                    $refereeData = array(
23253                        'id' => $userId,
23254                        'email' => $userData['email'],
23255                        'native_language2' => $userData['native_language2'],
23256                        'hash' => $userData['hash'],
23257                        'refereeName' => $userData['nickname'],
23258                        'referrerName' => $couponReferredData['referrerName'],
23259                        'couponAmount' => $couponReferredData['refereeSaveAmount'],
23260                        'couponUpdatedTotal' => $couponReferredData['refereeUpdatedTotal']
23261                    );
23262
23263                    // send mail to referee
23264                    myMailer::sendTemplateMail($couponMailId, $userData['email'], $refereeData, array(), 'User');
23265                }
23266
23267                // send coupon mail to referer
23268                if (isset($couponReferredData['sendMailToReferer']) && $couponReferredData['sendMailToReferer']) {
23269                    $referrerData = array(
23270                        'id' => $couponReferredData['referrerId'],
23271                        'email' => $couponReferredData['referrerEmail'],
23272                        'native_language2' => $couponReferredData['nativeLanguage2'],
23273                        'hash' => $couponReferredData['referrerHash'],
23274                        'refereeName' => $userData['User']['nickname'],
23275                        'referrerName' => $couponReferredData['referrerName'],
23276                        'couponAmount' => $couponReferredData['refererSaveAmount'],
23277                        'couponUpdatedTotal' => $couponReferredData['refererUpdatedTotal']
23278                    );
23279
23280                    // send mail to referrer
23281                    myMailer::sendTemplateMail($couponMailId, $couponReferredData['referrerEmail'], $referrerData, array(), 'User');
23282                }
23283            }
23284
23285            $discountOption = isset($data['discountOption']) ? $data['discountOption'] : [];
23286            // if user plan has annual discount option
23287            if ($discountOption) {
23288                $contractStart = $formType != Configure::read('payment_credit_authentication') ? date('Y-m-d 00:00:00') : (isset($nextChargeDate) ? $nextChargeDate : $this->User->getFirstNextChargeDate());
23289                switch ($formType) {
23290                    case Configure::read('payment_credit_retry'):
23291                        $discountOption += [
23292                            'contract_start' => $contractStart,
23293                            'currency_code' => $currencyCode,
23294                            'payment_id' => $paymentId,
23295                            'dosh_settlement_status' => 1, // success
23296                            'form_type' => $formType
23297                        ];
23298
23299                        if (!$this->UserDiscountOptionsTerm->processMonthlyDiscountOption($discountOption)) {
23300                            $this->log(__METHOD__ . ' Failed to process monthly discount option. ' . json_encode($discountOption) . ' -- ' . json_encode($createOrderResult), $logFileName);
23301                            $dataSource->rollback();
23302                            return false;
23303                        }
23304                        break;
23305                    case Configure::read('payment_credit_force_charge'):
23306                        $doshStatus = $formType == Configure::read('payment_credit_authentication') ?
23307                            Configure::read('discount_option.dosh_status.subscription') :
23308                            Configure::read('discount_option.dosh_status.monthly_discount');
23309
23310                        // set data for user discount option term
23311                        $udotData = [
23312                            'userId' => $userId,
23313                            'discountOptionId' => $discountOption['discount_option_id'],
23314                            'discountOptionPriceId' => $discountOption['discount_option_price_id'],
23315                            'contractStart' => $contractStart,
23316                            'logFileName' => $logFileName,
23317                            'paymentId' => $paymentId,
23318                            'discountAmount' => $discountOption['amount'],
23319                            'doshEvent' => isset($discountOption['dosh_event']) ? $discountOption['dosh_event'] : Configure::read('discount_option.dosh_event.annual_discount'),
23320                            'currencyCode' => $currencyCode,
23321                            'doshStatus' => isset($discountOption['dosh_status']) ? $discountOption['dosh_status'] : $doshStatus,
23322                            'formType' => $formType
23323                        ];
23324
23325                        // create user discount option term
23326                        if (!$this->UserDiscountOptionsTerm->createTerm($udotData)) {
23327                            $this->log(__METHOD__ . ' Failed to create user discount option term. ' . json_encode($udotData) . ' -- ' . json_encode($createOrderResult), $logFileName);
23328                            $dataSource->rollback();
23329                            return false;
23330                        }
23331
23332                        $adoLogParams = [
23333                            'user_id' => $userId,
23334                            'platform' => $platform,
23335                            'status' => 1, // subscribe
23336                            'controller_name' => $this->request->params['controller'],
23337                            'action_name' => $this->request->params['action'],
23338                            'user_type' => 0, // normal user
23339                            'option_before' => '',
23340                            'option_after' => 1,
23341                            'option_before_name' => '',
23342                            'option_after_name' => 'Annual Discount Option',
23343                            'option_type' => 3, // annual discount option
23344                            'payment_plan_id' => $paymentPlanId
23345                        ];
23346
23347                        if (!$this->UserOptionChangeLog->saveOptionChangeLog($adoLogParams)) {
23348                            $this->log(__METHOD__ . ' Failed to update option change. ' . json_encode($adoLogParams) . ' -- ' . json_encode($createOrderResult), $logFileName);
23349                            $dataSource->rollback();
23350                            return false;
23351                        }
23352                        break;
23353                }
23354            }
23355
23356            $dataSource->commit();
23357
23358            // update payment transaction
23359            $this->updatePaymentTransaction(array(
23360                'id' => $ptId,
23361                'fields' => array(
23362                    'status' => 1, // success
23363                    'response_text' => array('paypal_result' => $paypalData)
23364                ),
23365                'logFileName' => $logFileName
23366            ));
23367
23368            $adjustParams = array(
23369                'formType' => $formType,
23370                'statusBefore' => isset($ptPaymentParams['statusBefore']) ? $ptPaymentParams['statusBefore'] : null,
23371                'userId' => $userId,
23372                'idfa' => $userData['idfa']
23373            );
23374            UserTable::sendEventToAdjust($adjustParams);
23375
23376            if ( //Amazon gift campaign
23377                in_array($formType, array($ftCardAuth, $ftForceCharge))
23378            ) {
23379                ClassRegistry::init('CampaignSettingTable')->amazonGift(array('user_id' => $userId, 'type' => 1));
23380            }
23381
23382            // Teacher Perks : Student re-enroll
23383            if ( $formType == Configure::read('payment_credit_force_charge')) {
23384                ClassRegistry::init('TeacherPerksAccount')->reEnroll(['user_id' => $userId]);
23385            }
23386
23387            //    NC-7644 Add code reward for re-enroolling with the campaign code
23388            $this->addCoinRewardForReenroll($userData);
23389
23390        
23391            // - NJ-18780 : add monthly coin for lite plan user 
23392            if (
23393                $formType == Configure::read('payment_lite_credit_paid') || 
23394                ($formType == Configure::read('payment_credit_retry') && $isLitePlanUser)
23395            ) {
23396                $this->liteUserAddCoinRewardForReenroll($userData);
23397            }
23398            
23399            return true;
23400        } else {
23401            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Paypal process payment - failed to create order', $paypalData, $createOrderResult);
23402        }
23403
23404        return false;
23405    }
23406    
23407    //    NC-7644 Add code reward for re-enroolling with the campaign code
23408    public function addCoinRewardForReenroll($userData = array()){
23409        $this->autoRender = false;
23410        /* 
23411            NC-7644  
23412            get the count of user deactivation enquate 
23413        */
23414        $deactivationEnquateCount = $this->UsersDeactivationEnquate->usersDeactivationEnquateCount($userData['id']);
23415        
23416        // NC-7644 user first_charge_date
23417        $firstChargeDatePlus7Days = date('Y-m-d H:i:s', strtotime($userData['first_charge_date'].'+ 7 days')); 
23418        $dateNow = date('Y-m-d H:i:s'); 
23419
23420        /*     NC-7644 get user membership type 
23421            NC-7644 ticket Need a return of `12` 12 => 'Free'
23422        */
23423        $userObj = new UserTable($userData);
23424        $userMembership = $userObj->getMembershipTypeIndex();
23425
23426        // NC-7644 get currency
23427        $userCurrencyCode = isset($userData['currency_code']) ? $userData['currency_code'] : Configure::read('default.user_currency');
23428
23429        // get the campaign `CC_RE10` unique memCached
23430        $mem = new myMemcached();
23431        $memKey = 'campaign_code_CC_RE10' . $userData['id'];
23432        $memKey2 = 're_enroll_cc_re10' . $userData['id'];
23433        $hasCampaignCode = $mem->get($memKey);
23434        $mem->delete($memKey);
23435        $mem->delete($memKey2);
23436        
23437        /*     get `CC_RE10` the campaign id 
23438            get the envi event id
23439        */
23440        $coinEnviEventId = Configure::read('campaign_config.coin_event_id.reenroll');
23441        $coinEventId = $coinEnviEventId[Configure::read('ENVIRONMENT')];
23442        
23443        // chect if has already this campaign event id to the coin boxes table
23444        $hasReceivedCoin = $this->CoinBox->checkUserFirstTimeReceivedRewardCoin($userData['id'], $coinEventId);
23445        
23446        $this->log(__METHOD__ ."sai_debug -> Add 500 Coin Reward for firstChargeDatePlus7Days: ".json_encode($firstChargeDatePlus7Days), "debug");
23447        $this->log(__METHOD__ ."sai_debug -> Add 500 Coin Reward for dateNow: ".json_encode($dateNow), "debug");
23448        $this->log(__METHOD__ ."sai_debug -> Add 500 Coin Reward for userCurrencyCode: ".json_encode($userCurrencyCode), "debug");
23449        $this->log(__METHOD__ ."sai_debug -> Add 500 Coin Reward for userMembership: ".json_encode($userMembership), "debug");
23450        $this->log(__METHOD__ ."sai_debug -> Add 500 Coin Reward for deactivationEnquateCount: ".json_encode($deactivationEnquateCount), "debug");
23451        $this->log(__METHOD__ ."sai_debug -> Add 500 Coin Reward for hasCampaignCode: ".json_encode($hasCampaignCode), "debug");
23452        $this->log(__METHOD__ ."sai_debug -> Add 500 Coin Reward for corporate_id: ".json_encode($userData['corporate_id']), "debug");
23453        $this->log(__METHOD__ ."sai_debug -> Add 500 Coin Reward for studysapuri_id: ".json_encode($userData['studysapuri_id']), "debug");
23454        $this->log(__METHOD__ ."sai_debug -> Add 500 Coin Reward for hasReceivedCoin: ".json_encode($hasReceivedCoin), "debug");
23455
23456
23457        $isLitePlanUser = in_array($userMembership, Configure::read('membership_type_lightplan')) ? true : false;
23458        
23459        if (
23460            $firstChargeDatePlus7Days < $dateNow                            // need expire 7 day trial
23461            // && $userCurrencyCode == Configure::read('currency_jpy')        // need to have a JPY currency : [NJ-37810] Change from JPY -> All Currencies 
23462            && $userMembership == 12                                        // need to have a  `Free` membership
23463            && $deactivationEnquateCount == 1                                // need to have only 1 user deactivation enquate
23464            && (isset($hasCampaignCode) && $hasCampaignCode)                // need have a campaign code `CC_RE10`
23465            && !$userData['corporate_id'] && !$userData['studysapuri_id']    // need not a user corporate or sapuri
23466            && !$hasReceivedCoin
23467            &&    !$isLitePlanUser                                         // user will recieved this once
23468        ) {
23469            
23470            // grant 500 coins for re-enrolling with 1 users_deactivation_enquates
23471            $coinReward = 500;
23472            
23473            // insert coin boxes
23474            ClassRegistry::init('CoinBox')->clear();
23475            $rewardParams = array(
23476                'status'         => 1,
23477                'user_id'         => $userData['id'],
23478                'coin_event_id'    => $coinEventId,
23479                'coin'             => $coinReward
23480            );
23481            $addCoinReward = ClassRegistry::init('CoinBox')->addCoinReward($rewardParams);
23482            $this->log(__METHOD__ ."sai_debug -> Add 500 Coin Reward for re-enroll: ".json_encode($addCoinReward), "debug");
23483            if (!$addCoinReward) {
23484                $this->log(__METHOD__ ."sai_debug -> unable to add coin reward data: ".json_encode($rewardParams), "debug");
23485            }
23486        }
23487        // NC-7644 end of code
23488    }
23489    
23490    private function paypalSaveBillingAgreement($data = array(), $userData = array()) {
23491        $logFileName = 'paypal_debug';
23492        $ret = array('success' => false);
23493
23494        $memKey = 'paypalBillingAgreementData_' . $userData['api_token'];
23495        // return false if memcache billing agreement data does not exist
23496        if (!$paypalData = $this->memcache->get($memKey)) {
23497            $this->log(__METHOD__ . ' Memcached billing agreement data does not exist. --> ' . json_encode($paypalData) . ' | data --> ' . json_encode($data) . ' | user data --> ' . json_encode($userData), $logFileName);
23498            return $ret;
23499        }
23500
23501        // set paypal data
23502        $ret['paypalData'] = $paypalData;
23503
23504        if (
23505            !isset($paypalData['accessTokenData']['access_token']) || 
23506            !isset($paypalData['finalizeBillingAgreementData']['id']) ||
23507            !isset($paypalData['finalizeBillingAgreementData']['payer']['payer_info']['payer_id']) ||
23508            !isset($paypalData['finalizeBillingAgreementData']['payer']['payer_info']['email'])
23509        ) {
23510            $this->log(__METHOD__ . ' Missing billing agreement param(s). --> ' . json_encode($paypalData), $logFileName);
23511            return $ret;
23512        }
23513
23514        $formType = $data['formType'];
23515        $accessToken = $paypalData['accessTokenData']['access_token'];
23516        $baId = $paypalData['finalizeBillingAgreementData']['id']; // billing agreement id
23517        $payerId = $paypalData['finalizeBillingAgreementData']['payer']['payer_info']['payer_id'];
23518        $payerEmail = $paypalData['finalizeBillingAgreementData']['payer']['payer_info']['email'];
23519        $userData['payment_plan_id'] = $data['paymentPlanData']['paymentPlanId'];
23520        $userData['price_id'] = $data['paymentPlanData']['priceId'];
23521        $userData['paymentAmount'] = 0;
23522
23523        // - NJ-18780 : change to correct form type 
23524        if (
23525            $formType != Configure::read('payment_credit_change') &&
23526            in_array($userData['payment_plan_id'], Configure::read('lite_payment_plans'))
23527        ) {
23528            $formType = myTools::getLitePlanUserFormType(Configure::read('payment_plans.light_plan_free'));
23529        }
23530
23531        // add if subscribe to annual discount option
23532        if (isset($data['discountOption'])) {
23533            $userData['discountOption'] = $data['discountOption'];
23534        }
23535
23536        // return false if failed to create payment transaction
23537        if (!$pt = $this->createPaymentTransaction($formType, $userData)) {
23538            $this->log(__METHOD__ .' Failed to save payment transaction. Params --> ' . json_encode($userData), $logFileName);
23539            return $ret;
23540        }
23541
23542        $paymentHash = $pt['payment_hash'];
23543        $ret['ptId'] = $ptId = $pt['id'];
23544        $userId = $userData['id'];
23545        $currencyCode = Configure::read('default.user_currency');
23546
23547        $this->User->openDBReplica();
23548        $user = $this->User->find('first', array(
23549            'conditions' => array('User.id' => $userId)
23550        ));
23551        $this->User->closeDBReplica();
23552        
23553        $currency_before = !is_null($user['User']['currency_code']) ? $user['User']['currency_code'] : $currencyCode;
23554        $plan_before = !is_null($user['User']['payment_plan_id']) ? $user['User']['payment_plan_id'] : $userData['payment_plan_id'];
23555        // load PayPal class
23556        if (!class_exists('PayPal')) {
23557            App::import('Lib', 'PayPal');
23558        }
23559
23560        $paypal = new PayPal();
23561
23562        $createOrderParams = array(
23563            'accessToken' => $accessToken,
23564            'paypalRequestId' => $ptId,
23565            'intent' => 'AUTHORIZE',
23566            'paymentHash' => $paymentHash,
23567            'userId' => $userId,
23568            'currencyCode' => $currencyCode,
23569            'amount' => 1,
23570            'billingAgreementId' => $baId
23571        );
23572
23573        // create order
23574        $orderResult = $paypal->createOrder($createOrderParams);
23575        $ret['paypalData']['create_order_data'] = $orderResult;
23576
23577        if (!isset($orderResult['status']) || (isset($orderResult['status']) && $orderResult['status'] !== 'COMPLETED')) {
23578            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Paypal save billing agreement - failed to create order', $paypalData, $createOrderParams);
23579            $this->log(__METHOD__ . ' Create order error. --> ' . json_encode($orderResult) . ' | params --> ' . json_encode($createOrderParams) . ' | paypal data --> ' . json_encode($paypalData), $logFileName);
23580            return $ret;
23581        }
23582
23583        $authorizationVoidParams = array(
23584            'accessToken' => $accessToken,
23585            'authorizationId' => $orderResult['purchase_units'][0]['payments']['authorizations'][0]['id']
23586        );
23587
23588        // void authorization
23589        // expected return empty if success
23590        $voidResult = $paypal->authorizationVoid($authorizationVoidParams);
23591        $ret['paypalData']['authorization_void_data'] = $voidResult; // expected empty
23592
23593        if (!empty($voidResult)) {
23594            $this->log(__METHOD__ . ' authorization void error. --> ' . json_encode($voidResult) . ' | params --> ' . json_encode($authorizationVoidParams) . ' | paypal data --> ' . json_encode($paypalData), $logFileName);
23595            return $ret;
23596        }
23597
23598        $cardCompany = Configure::read('card_company.paypal');
23599
23600        if ($formType == Configure::read('payment_credit_authentication')) {
23601            $param1 = "paypal reregister, payment transaction id: {$ptId}";
23602        } else {
23603            $param1 = "paypal change, payment transaction id: {$ptId}";
23604        }
23605
23606        // initialize transaction
23607        $dataSource = $this->User->getDataSource();
23608        $dataSource->begin();
23609
23610        $savePaymentArr = array(
23611            'user_id' => $userId,
23612            'amount' => 0,
23613            'status' => 1,
23614            'reference_id' => $userId,
23615            'payment_transaction_password' => $pt['password'],
23616            'card_company' => $cardCompany,
23617            'param1' => $param1,
23618            'form_type' => $formType,
23619            'ordd' => $paymentHash,
23620            'transaction_code' => $paymentHash,
23621            'currency_id' => Configure::read('default.settlement_currency_id'), // set currency id to jpy
23622            'currency_code' => $currencyCode,
23623            'payment_id' => $userData['payment_plan_id'],
23624            'price_id' => $userData['price_id'],
23625            'payment_type' => Configure::read('payment_types.payment_plan'),
23626            'discounted_amount' => isset($userData['discounted_amount']) ? $userData['discounted_amount'] : 0
23627        );
23628
23629        // create new payment
23630        $this->Payment->clear();
23631        $this->Payment->create();
23632        $this->Payment->set($savePaymentArr);
23633        if (!$this->Payment->save()) {
23634            $this->log(__METHOD__ . ' Failed to save payment data. --> ' . json_encode($savePaymentArr) . ' | paypal data --> ' . json_encode($paypalData), $logFileName);
23635            $dataSource->rollback();
23636            return $ret;
23637        }
23638
23639        // set payment_id
23640        $paymentSaveID = $this->Payment->id;
23641
23642        //update/add user`s settlement amount
23643        $this->User->updateUserPayments($savePaymentArr);
23644
23645        $dateNow = date('Y-m-d H:i:s');
23646        $saveUserArr = array(
23647            'status' => 1,
23648            'modified' => $dateNow,
23649            'fail_flg' => 0,
23650            'charge_flg' => 1,
23651            'counseling_attended_flg' => 0,
23652            'card_company' => $cardCompany,
23653            'hash16' => $userId,
23654            'last_charge_date' => $dateNow,
23655            'paypal_billing_agreement_id' => $baId,
23656            'paypal_payer_id' => $payerId,
23657            'paypal_payer_email' => $payerEmail,
23658            'payment_plan_id' => $userData['payment_plan_id'],
23659            'price_id' => $userData['price_id'],
23660            'card_expiration_date' => null
23661        );
23662
23663
23664        // NJ-1562 - appreciation on
23665        if( $userData['payment_plan_id'] && in_array( $userData['payment_plan_id'], Configure::read('appreciation.payment_plan_id') ) ) {
23666            $saveUserArr['allow_appreciation_flg'] = 1; // on
23667            //NJ-7874 Turn Off appreciation settings for Family Plan (Default)
23668            if (in_array($userData['payment_plan_id'], Configure::read('appreciation.can_coin_purchase_check')) ) {
23669                $saveUserArr['allow_appreciation_flg'] = 0;
23670                $saveUserArr['show_appreciation_flg'] = 0;
23671                $saveUserArr['tip_max_amount'] = null;
23672            } else {
23673                $userBirthday  = $userData['User']['birthday'] ?? $userData['birthday'];
23674                $userAge = UserTable::getStudentAge($userBirthday);
23675                $userAge = $userAge ? (int) $userAge : null;
23676
23677                //default show appreciation flg
23678                $showAppreciationFlg = 0;
23679
23680                //change the show appreciation flg if no birthday set or 18 and above            
23681                if (!$userAge || $userAge >= 18) {
23682                    $showAppreciationFlg = 1;
23683                }
23684
23685                //set the show appreciation show
23686                $saveUserArr['show_appreciation_flg'] = $showAppreciationFlg; // set
23687            }
23688        }
23689
23690        $nextChargeDate = $this->User->getFirstNextChargeDate();
23691        if (
23692            $formType == Configure::read('payment_credit_authentication') || 
23693            $formType == Configure::read('payment_lite_credit_free') ||
23694            $formType == Configure::read('payment_credit_chocotto_free')
23695        ) {
23696            $saveUserArr['next_charge_date'] = $nextChargeDate;
23697        }
23698
23699        // NC-7779 : check if user has chivox monthly test taken for the current month, and monthly_speaking_attended_flg ON,
23700        // turn Off the flag if users has not yet taken the exam for the current month.
23701        // @TODO check query
23702        if (
23703            isset($userData['monthly_speaking_attended_flg']) && isset($userData['monthly_speaking_business_attended_flg']) &&
23704            ($userData['monthly_speaking_attended_flg'] == 1 || $userData['monthly_speaking_business_attended_flg'] == 1)
23705        ) {
23706
23707            // check chivox monthly
23708            $paymentPlanIdsForChivoxMonthly = Configure::read('chivox.monthly.user_payment_plan_cantake_exam');
23709            if (in_array($userData['payment_plan_id'], $paymentPlanIdsForChivoxMonthly)) {
23710
23711                // load model
23712                $this->loadModel("UsersChivoxMonthlyTest");
23713                $userTestMonthFlag = $this->UsersChivoxMonthlyTest->checkUserCurrentMonthExam(array('user_id' => $userId));
23714
23715                $monthlySpeakingAttendedFlg = Configure::read('chivox.test_data_test_type.daily'); // test_type daily speaking 0
23716                $monthlySpeakingBusinessAttendedFlg = Configure::read('chivox.test_data_test_type.business'); // test_type business 1
23717
23718                // if user hat not yet taken the exam for current month
23719                if (!in_array($monthlySpeakingAttendedFlg, $userTestMonthFlag)) {
23720                    $saveUserArr['monthly_speaking_attended_flg'] = 0;
23721                }
23722                if (!in_array($monthlySpeakingBusinessAttendedFlg, $userTestMonthFlag)) {
23723                    $saveUserArr['monthly_speaking_business_attended_flg'] = 0;
23724                }
23725            }
23726        }
23727
23728        $this->User->read(array_keys($saveUserArr), $userId);
23729        $this->User->set($saveUserArr);
23730        $this->User->validate = array();
23731        if (!$this->User->save()) {
23732            $this->log(__METHOD__ . ' Failed to update user data. --> ' . json_encode($saveUserArr) . ' | user id --> ' . $userId . ' | paypal data --> ' . json_encode($paypalData), $logFileName);
23733            $dataSource->rollback();
23734            return $ret;
23735        }
23736
23737
23738        // decode
23739        $ptPaymentParams = json_decode($pt['payment_params'], true);
23740
23741        if (
23742            $formType == Configure::read('payment_credit_authentication') || 
23743            $formType == Configure::read('payment_lite_credit_free') ||
23744            $formType == Configure::read('payment_credit_chocotto_free') 
23745        ) {
23746            $platform = $userData['platform'];
23747            // if plaftorm is empty
23748            if (!isset($platform)) {
23749                $platform = myTools::mobappDetectPlatform();
23750                if ($this->params->params['action'] == 'mobapp_paypal_credit_register_process') {
23751                    $platform = myTools::mobappDetectPlatform();
23752                } else {
23753                    $platform = Configure::read('platform.pclp');
23754                    if ($this->RequestHandler->isMobile()) {
23755                        $platform = Configure::read('platform.splp');
23756                    }
23757                }
23758
23759                // update platform
23760                $this->User->updateUserPlatform($userId, $platform);
23761            }
23762            $currentUser = $this->User->find('first', array(
23763                'fields' => array('User.parent_id', 'User.currency_code', 'User.payment_plan_id'),
23764                'conditions' => array('User.id' => $userId),
23765                'recursive' => -1
23766            ));
23767            $parentId = $currentUser['User']['parent_id'];
23768            $is_cron = 0;
23769            if (php_sapi_name() == 'cli'){
23770                $is_cron = 1;
23771            } 
23772               $currency_after = $currentUser['User']['currency_code'];
23773               $plan_after = $currentUser['User']['payment_plan_id'];
23774            $usclData = array(
23775                'user_id' => $userId,
23776                'platform' => $platform ?? '',
23777                'card_company_before' => '',
23778                'status_before' => $ptPaymentParams['statusBefore'],
23779                'status_after' => $ptPaymentParams['statusAfter'],
23780                'controller_name' => $this->request->params['controller'],
23781                'action_name' => $this->request->params['action'],
23782                'parent_id' => $parentId,
23783                'is_cron' => $is_cron,
23784                'currency_before' => $currency_before,
23785                'currency_after' => $currency_after,
23786                'payment_plan_id_before' => $plan_before,
23787                'payment_plan_id_after' => $plan_after
23788            );
23789
23790            // save user change membership status
23791            if (!$this->UserStatusChangeLog->saveLog($usclData)) {
23792                $this->log(__METHOD__ . ' Failed to save user status change log data. --> ' . json_encode($usclData) . ' | paypal data --> ' . json_encode($paypalData), $logFileName);
23793                $dataSource->rollback();
23794                return $ret;
23795            }
23796        }
23797
23798        // if parent user update children's card company
23799        if ($formType == Configure::read('payment_credit_change')) {
23800            $childList = $this->User->getChildId($userId);
23801            // check if user is parent
23802            if (!empty($childList)) {
23803                foreach ($childList as $childId) {
23804                    $this->User->clear();
23805                    $updateCCArr = array('card_company' => $cardCompany);
23806                    if (!$this->User->read(array_keys($updateCCArr), $childId)) {
23807                        $this->log(__METHOD__ . ' child id does not exist.  --> ' . json_encode($updateCCArr) . ' | parent id --> ' . $userId . ' | paypal data --> ' . json_encode($paypalData), $logFileName);
23808                        $dataSource->rollback();
23809                        return $ret;
23810                    }
23811
23812                    $this->User->set($updateCCArr);
23813                    if (!$this->User->save()) {
23814                        $this->log(__METHOD__ . ' failed to update child card company.   --> ' . json_encode($updateCCArr) . ' | parent id --> ' . $userId . ' | paypal data --> ' . json_encode($paypalData), $logFileName);
23815                        $dataSource->rollback();
23816                        return $ret;
23817                    }
23818                }
23819            }
23820        }
23821
23822        $annualDiscountOption = isset($userData['annualDiscountOption']) ? $userData['annualDiscountOption'] : []; 
23823        // if user plan has annual discount option
23824        if ($annualDiscountOption && $formType == Configure::read('payment_credit_authentication')) {
23825            // set data for user discount option term
23826            $udotData = [
23827                'userId' => $userId,
23828                'discountOptionId' => $annualDiscountOption['discount_option_id'],
23829                'discountOptionPriceId' => $annualDiscountOption['discount_option_price_id'],
23830                'contractStart' => isset($nextChargeDate) ? $nextChargeDate : $this->User->getFirstNextChargeDate(),
23831                'logFileName' => $logFileName,
23832                'paymentId' => $paymentSaveID,
23833                'discountAmount' => $annualDiscountOption['amount'],
23834                'doshEvent' => Configure::read('discount_option.dosh_event.annual_discount'),
23835                'currencyCode' => $currencyCode,
23836                'doshStatus' => Configure::read('discount_option.dosh_status.subscription')
23837            ];
23838
23839            // create user discount option term
23840            if (!$this->UserDiscountOptionsTerm->createTerm($udotData)) {
23841                $this->log(__METHOD__ . 'Failed to create user discount option term. ' . json_encode($udotData) . ' | paypal data --> ' . json_encode($paypalData), $logFileName);
23842                $dataSource->rollback();
23843                return $ret;
23844            }
23845
23846            $adoLogParams = [
23847                'user_id' => $userId,
23848                'platform' => $userData['platform'],
23849                'status' => 1, // subscribe
23850                'controller_name' => $this->request->params['controller'],
23851                'action_name' => $this->request->params['action'],
23852                'user_type' => 0, // normal user
23853                'option_before' => '',
23854                'option_after' => 1,
23855                'option_before_name' => '',
23856                'option_after_name' => 'Annual Discount Option',
23857                'option_type' => 3, // annual discount option
23858                'payment_plan_id' => $userData['payment_plan_id']
23859            ];
23860
23861            if (!$this->UserOptionChangeLog->saveOptionChangeLog($adoLogParams)) {
23862                $this->log(__METHOD__ . ' Failed to update option change. ' . json_encode($adoLogParams) . ' | paypal data --> ' . json_encode($paypalData), $logFileName);
23863                $dataSource->rollback();
23864                return $ret;
23865            }
23866        }
23867
23868        $ptUpdateParams = array(
23869            'id' => $pt['id'],
23870            'fields' => array(
23871                'status' => 1,
23872                'response_text' => $ret['paypalData']
23873            ),
23874            'logFileName' => $logFileName
23875        );
23876
23877        // update payment transaction
23878        if (!$this->PaymentTransaction->updateWPPaymentTransaction($ptUpdateParams)) {
23879            $this->log(__METHOD__ . ' Failed to update payment transaction. --> ' . json_encode($ptUpdateParams) . ' | paypal data --> ' . json_encode($paypalData), $logFileName);
23880            $dataSource->rollback();
23881            return $ret;
23882        }
23883
23884        $dataSource->commit();
23885
23886        if (isset($ptPaymentParams['userRegister']) && $ptPaymentParams['userRegister']) {
23887            UsersPointHistoryTable::checkDailyBonus($userId);
23888
23889            $receiveBonus = UsersPointTable::checkIfUserReceiveBonusUponRegister($userId);
23890            if (
23891                !$receiveBonus &&
23892                empty($userData['User']['complimentary_code']) &&
23893                !in_array(
23894                    $formType,
23895                    [
23896                        Configure::read('payment_credit_chocotto_free'),
23897                        Configure::read('payment_credit_chocotto_monthly_payment')
23898                    ]
23899                )
23900            ) {
23901                UsersPointTable::giveBonusCoins(['userId' => $userId, 'triggerNo' => 1]);
23902            } 
23903
23904            $this->User->clear();
23905            $_currentUser = $this->User->read(array('id','memo','payment_plan_id'), $userId);
23906            $_currentUserMemo = $_currentUser['User']['memo'];
23907
23908            # update user memo
23909            $_coins = Configure::read('credit.lite_plan_bonus_coin_authentication');
23910            $_dateNow = date('Y-m-d H:i:s');
23911            $_updateMemo =  "\n {$_dateNow} Light Plan Bonus: {$_coins}";
23912            $_updateMemo = $_updateMemo . "\n" . $_currentUserMemo;
23913
23914            // - update user memo 
23915            $this->User->clear();
23916            $memUpdateParams = array(
23917                'id' => $userId,
23918                'memo' => $_updateMemo
23919            );
23920            $this->User->set($memUpdateParams);
23921            $this->User->save();
23922        }
23923
23924        // campaign master trigger 5
23925        $this->retrial_confiscate_coins([
23926            'formType' => $formType,
23927            'paymentPlanId' => $userData['payment_plan_id'],
23928            'userId' => $userId
23929        ]);
23930
23931        // send event to adjust
23932        $adjustParams = array(
23933            'formType' => $formType,
23934            'statusBefore' => isset($ptPaymentParams['statusBefore']) ? $ptPaymentParams['statusBefore'] : null,
23935            'userId' => $userId,
23936            'idfa' => $userData['idfa']
23937        );
23938        UserTable::sendEventToAdjust($adjustParams);
23939
23940        return array('success' => true);
23941    }
23942
23943    private function setSupportPayPal($user = array()) {
23944        $supportPayPal = true;
23945        if (isset($user['corporate_id']) && $user['corporate_id']) {
23946            $supportPayPal = false;
23947        }
23948
23949        $memKey = '';
23950        switch ($this->params->params['action']) {
23951            case 'payment_credit_register':
23952                $memKey = 'creditReregisterPaymentGatewayType_';
23953                break;
23954            case 'payment_credit_retry':
23955                $memKey = 'creditRetryPaymentGatewayType_';
23956                break;
23957            case 'payment_credit_charge':
23958                $memKey = 'creditChargePaymentGatewayType_';
23959                break;
23960            case 'payment_credit_change':
23961                $memKey = 'creditChangePaymentGatewayType_';
23962                break;
23963            case 'mobapp_credit_register':
23964                $memKey = 'mobappCreditReregisterPaymentGatewayType_';
23965                break;
23966            case 'mobapp_credit_retry':
23967                $memKey = 'mobappCreditRetryPaymentGatewayType_';
23968                break;
23969            case 'mobapp_credit_charge':
23970                $memKey = 'mobappCreditChargePaymentGatewayType_';
23971                break;
23972            case 'mobapp_credit_change':
23973                $memKey = 'mobappCreditChangePaymentGatewayType_';
23974                break;
23975        }
23976
23977        if ($supportPayPal) {
23978            $this->set('paypalFlg', true);
23979        }
23980
23981        $isCardRegistered = (!empty($user['card_brand']) && !empty($user['card_number'])) ? true : false;
23982
23983        $paymentGatewayType = Configure::read('card_company.zeus');
23984        if (!empty($memKey)) {
23985            $memData = $this->memcache->get($memKey . $user['api_token']);
23986            $paymentGatewayType = $memData ? $memData : $paymentGatewayType;
23987        }
23988
23989        $this->set('supportPayPal', $supportPayPal);
23990        $this->set('isCardRegistered', $isCardRegistered);
23991        $this->set('paymentGatewayType', $paymentGatewayType);
23992        $this->set('zeusCC', Configure::read('card_company.zeus'));
23993        $this->set('paypalCC', Configure::read('card_company.paypal'));
23994        $this->setPaypalUser($user);
23995    }
23996    /**
23997     * @api {post} /payment/sms_questionnaire sms_questionnaire()
23998     * @apiName sms_questionnaire
23999     * @apiGroup Payment
24000     * @apiDescription Redirect to sms_questionnaire page
24001     * 
24002     * @apiSuccess {View} Redirect Redirect to sms_questionnaire page
24003     * 
24004     * @apiSuccessExample Success Response:
24005     * Redirects to {{ENV}}/account/sms_questionnaire
24006     * 
24007     * @apiSampleRequest off
24008     */
24009    public function sms_questionnaire() {
24010        $data = array(
24011            'origin_url' => '/payment/payment_credit_register',
24012            'success_url' => '/payment/payment_credit_register'
24013        );        
24014        $this->Session->write($data);
24015        return $this->redirect('/account/sms_questionnaire');
24016    }
24017
24018    private function restrictForTrialNotConducted($userData, $urlParams) {
24019        $user = new UserTable($userData);
24020        $membershipTypeIndex = $user->getMembershipTypeIndex();
24021        // no free trial for corporate individual users
24022        if ($membershipTypeIndex == 13 && empty($user->corporate_id) && myTools::isDateEmpty($user->first_charge_date)) {
24023            return $this->redirect(myTools::getUrl() . '/mobapp/plan/trial'.$urlParams);
24024        }
24025    }
24026
24027    public function zeuspayGetChallenge() {
24028        $this->autoLayout = false;
24029        $this->autoRender = false;
24030        
24031        // - get user data
24032        $data = $this->request->data;
24033        $data['corpIndiUser'] ??= '';
24034
24035        if(!empty($data['userApiToken'])) {
24036            $this->User->openDBReplica();
24037            $appUserData = $this->User->find('first', array(
24038                'fields' => array(
24039                    'User.id',
24040                    'User.status',
24041                ),
24042                'conditions' => array('User.api_token' => $data['userApiToken']),
24043                'recursive' => -1,
24044            ));
24045            $this->User->closeDBReplica();
24046
24047            if ($appUserData) {
24048                $this->isWithdrawn = (isset($appUserData['User']['status']) && $appUserData['User']['status'] == 9) ? true : $this->isWithdrawn;
24049            }
24050        }
24051
24052        $this->log('NJ-61937 - Blocking the Payment/zeuspayGetChallenge');
24053        $appVersion = isset($data['appVersion']) && !empty($data['appVersion']) ? $data['appVersion'] : 0;
24054        $deviceType = isset($data['deviceType']) && !empty($data['deviceType']) ? $data['deviceType'] : 0;
24055        if ($this->IpBlock->blocked() || $this->isWithdrawn) {
24056            if(!empty($appVersion) && !empty($deviceType)) {
24057                if (in_array($deviceType, [1,2,3])) {
24058                    $appVersionCompare = version_compare($appVersion, Configure::read('ip_block_app_version')[$deviceType], '<');
24059                    if (!$appVersionCompare) {
24060
24061                        $response = array(
24062                            'status' => 'blocked',
24063                            'isblocked' => 1,
24064                            'redirect_url_mobapp' => 'nativecamp://view/is_blocked',
24065                        );
24066
24067                        return json_encode($response);
24068                    }
24069                }
24070            } else if(empty($data['userApiToken'])) {
24071                $response = array(
24072                    'status' => 'blocked',
24073                    'isblocked' => 1,
24074                    'redirect_url' => myTools::getUrl()
24075                );
24076                $this->Auth->logout();
24077                if ($this->Session->read('check-step2')) {
24078                    $this->Session->delete('check-step2');
24079                }    
24080        
24081                if ($this->Session->read('check-step1')) {
24082                    $this->Session->delete('check-step1');
24083                }
24084                return json_encode($response);
24085            }
24086        }
24087
24088        $this->log('[ZeusJhayr] challenge data --> ' . json_encode($data), 'debug');
24089        // - if has recaptcha
24090        if (isset($data['g-recaptcha-response'])) {
24091            if (empty($data['g-recaptcha-response']) || !$data['g-recaptcha-response']) {
24092                $message = 'reCAPTCHA failed : error code 03';
24093                $this->Session->setFlash($message, '', array(), 'flashfailcaptcha');
24094                return 'captcha_error';
24095            }
24096        }
24097
24098        $originalAmount = isset($data['ZPaymentFullLogs']['money']) ? $data['ZPaymentFullLogs']['money'] : 0;
24099        $zFormType = isset($data['z_payment_form_type']) ? $data['z_payment_form_type'] : '';
24100        $studyAbroadFlg = $zFormType == Configure::read('payment_study_abroad') ? true : false;
24101
24102        // NJ-28462 Create Payment Transaction Corp Individual
24103        if( $data['corpIndiUser'] && !$studyAbroadFlg) {
24104            $corpIndiPT = $this->createCorporateIndividualPayment($data);
24105            $data['ZPaymentFullLogs']['paymentHash'] = $corpIndiPT['paymentHash'];
24106            $data['ZPaymentFullLogs']['money'] = $corpIndiPT['paymentAmount'];
24107        }
24108
24109        // corporate data
24110        $corporateId = $this->Session->read('corporateCompanyID');
24111        $rUserId = $corporateId;
24112        if (!empty($corporateId) && !$studyAbroadFlg){
24113            $corporateData = $this->Corporate->find("first",array(
24114                    "conditions" => array( "Corporate.id" => $corporateId),
24115                    "fields" => array("Corporate.email","Corporate.name"),
24116                    "recursive" => -1,
24117                )
24118            );
24119            $pData = array(
24120                'clientIp' => Configure::read('ZEUS_clientip'), # client ip
24121                'cardNumber' => $data['zeus_token_card_number'], # card number
24122                'expyy' => !empty($data['zeus_token_card_expires_year']) ? $data['zeus_token_card_expires_year'] : "0", # expired year
24123                'expmm' => !empty($data['zeus_token_card_expires_month']) ? $data['zeus_token_card_expires_month'] : "0", # expired month
24124                'telNo' => Configure::read('credit.default_telno'), # telephone number
24125                'email' => $corporateData['Corporate']['email'], # email
24126                'username' => mb_strtoupper($corporateData['Corporate']['name']), # username
24127                'sendId' => 'cz' . $corporateId, # id
24128                'money' => isset($data['ZPaymentFullLogs']['money']) ? (int)$data['ZPaymentFullLogs']['money'] : 0, # money
24129                'tokenKey' => $data["ZPaymentFullLogs"]['zeusTokenValue'],
24130                'paymentHash' => $data["ZPaymentFullLogs"]['paymentHash']
24131            );
24132        } else {
24133            $getData = $this->request->query;
24134            $userId = isset($data['userID']) && !empty($data['userID']) ? $data['userID'] : $this->Session->read('register_user_id');
24135
24136            $userToken = isset($data['userApiToken']) ? $data['userApiToken'] : '';
24137            $appVersion = isset($data['appVersion']) ? $data['appVersion'] : '';
24138            $deviceType = isset($data['deviceType']) ? $data['deviceType'] : '';
24139
24140            if (!empty($userToken)) {
24141                $condition = array('User.api_token' => $userToken);
24142            } else {
24143                $condition = array('User.id' => $userId);
24144            }
24145
24146            // - get user data
24147            $userData = $this->User->getUserDataUsingMasterDb(
24148                'first',
24149                $condition,
24150                array(
24151                    'User.email',
24152                    'User.id',
24153                    'User.parent_id',
24154                    'User.charge_flg',
24155                    'User.corporate_id',
24156                    'User.complimentary_code',
24157                    'User.currency_code',
24158                    'User.payment_plan_id',
24159                    'User.price_id',
24160                    'User.api_token',
24161                    'User.hash16',
24162                    'User.status',
24163                    'User.fail_flg',
24164                    'User.double_check_flg',
24165                    'User.phone_number',
24166                    'User.country_code',
24167                    'User.idfa',
24168                    'User.memo'
24169                )
24170            );
24171            $userCountryCode = $this->CountryCode->find('first', array(
24172                'conditions' => array(
24173                    'CountryCode.code' => $userData['User']['country_code']
24174                ),
24175                'recursive' => -1
24176            ));
24177            $userPayment = $this->Payment->find('all', [
24178                'conditions' => ['Payment.user_id' => $userData['User']['id']],
24179                'fields' => ['Payment.id'],
24180                'recursive' => -1 
24181            ]);
24182            $lastModifiedDate = date('YmdHis');
24183            $blockResult = $this->ZeusAccountBlock->processBlock($data);
24184            if (!empty($blockResult['status'])) {
24185                $requestParams = array(
24186                    'controller_origin' => $this->request->params['controller'],
24187                    'action_origin' => $this->request->params['action']
24188                );
24189                $userIdfaKey = !empty($userData['User']['idfa']) ? $userData['User']['idfa'] : null;
24190                $mobappUrlParam = '';
24191                if (!empty($userData['User']['idfa'])) {
24192                    $userIdfaKey = $userData['User']['idfa'];
24193                    if ($homeIdfaKey =  $this->memcache->get($userIdfaKey)) {
24194                        $mobappHomeParam = http_build_query($homeIdfaKey);
24195                        $mobappUrlParam = "/mobapp/home?is_block=1&{$mobappHomeParam}";
24196                    }
24197                }
24198                $this->User->forceWithdrawal($userData, $lastModifiedDate,$requestParams, $blockResult['id'], 0);
24199
24200                $redirect_url_mobapp = myTools::getUrl() . $mobappUrlParam;
24201
24202                if(!empty($appVersion) && !empty($deviceType)) {
24203                    if (in_array($deviceType, [1,2,3])) {
24204                        $appVersionCompare = version_compare($appVersion, Configure::read('ip_block_app_version')[$deviceType], '<');
24205                        if (!$appVersionCompare) {
24206                            $redirect_url_mobapp = 'nativecamp://view/is_blocked';
24207                        }
24208                    }
24209                }
24210
24211                $response = array(
24212                    'status' => 'blocked',
24213                    'isblocked' => 1,
24214                    'redirect_url' => myTools::getUrl(),
24215                    'redirect_url_mobapp' => $redirect_url_mobapp,
24216                    'data' => $blockResult
24217                );
24218                $this->Auth->logout();
24219                if ($this->Session->read('check-step2')) {
24220                    $this->Session->delete('check-step2');
24221                }    
24222        
24223                if ($this->Session->read('check-step1')) {
24224                    $this->Session->delete('check-step1');
24225                }
24226                return json_encode($response);
24227            } 
24228            // - validate user membership type
24229            $userInfo = new UserTable($userData['User']);
24230            $memberindex = $userInfo->getMembershipTypeIndex();
24231            if (
24232                isset($data['z_payment_form_type']) &&
24233                $data['z_payment_form_type'] == Configure::read("payment_credit_retry") && // retry form
24234                $memberindex == 1 // premium user
24235            ) {
24236                // - redirect to mypage 
24237                return $this->redirect('/');
24238            }
24239
24240            # lite plan 
24241            if (
24242                isset($data['ZPaymentFullLogs']['payment_plan_type']) && 
24243                in_array(
24244                    $data['ZPaymentFullLogs']['payment_plan_type'],
24245                    [
24246                        Configure::read('register_plan_types.light'),
24247                        Configure::read('register_plan_types.light_with_zero_student_discount_option')
24248                    ]
24249                )
24250            ) {
24251                $discountOption = [];
24252                if ($data['ZPaymentFullLogs']['payment_plan_type'] == Configure::read('register_plan_types.light_with_zero_student_discount_option')) {
24253                    $zeroStudentDocument = isset($_FILES['zero_student_discount_application_documents_file']) ? $_FILES['zero_student_discount_application_documents_file'] : null;
24254                    // - redirect to mypage if uploaded docs is empty
24255                    if (empty($zeroStudentDocument)) {
24256                        return $this->redirect('/');
24257                    }
24258
24259                    // get discount option data
24260                    $discountOption = $this->DiscountOptionsPrice->getPaymentData([
24261                        'currencyCode' => Configure::read('currency_jpy'),
24262                        'discountOptionId' => Configure::read('discount_option.zero_student.plan_id')
24263                    ]);
24264
24265                    // redirect to mypage if discount option does not exist or is not enabled
24266                    if (!$discountOption) {
24267                        return $this->redirect('/');
24268                    }
24269
24270                    $discountOption += [
24271                        'dosh_event' => Configure::read('discount_option.dosh_event.student_discount'),
24272                        'dosh_status' => Configure::read('discount_option.dosh_status.monthly_discount'),
24273                        'option_after_name' => 'Zero Student Discount Option',
24274                        'option_type' => 4
24275                    ];
24276
24277                    $moveUploadedFile = StudentDiscountApplicationFormTable::moveUploadedFile([
24278                        'folder' => 'img/uploads',
24279                        'formData' => $zeroStudentDocument
24280                    ]);
24281
24282                    // redirect to mypage if failed transfer the uploaded file
24283                    if (!$moveUploadedFile) {
24284                        return $this->redirect('/');
24285                    }
24286
24287                    $uploadedData = [
24288                        'source' => $moveUploadedFile['source'],
24289                        'key' => $moveUploadedFile['key'],
24290                        'uploader_type' => 39, // proof of document
24291                        'uploader_id' => $userId,
24292                        'file' => $moveUploadedFile['file']
24293                    ];
24294
24295                    // upload file
24296                    $uploadFileSuccess = $this->FileStorage->uploadFile($uploadedData);
24297                    if (!$uploadFileSuccess) {
24298                        return $this->redirect('/');
24299                    }
24300
24301                    $discountOption['application_form_app_image_url'] = $uploadFileSuccess['FileStorage']['url'];
24302
24303                    
24304                }
24305
24306                $form_type = isset($data['z_payment_form_type']) ? $data['z_payment_form_type'] : 0;
24307
24308                # no need to change the hash for retry and change form type
24309                if (
24310                    $form_type != Configure::read("payment_credit_retry") && 
24311                    (!isset($data['zeus_change_card']) || !$data['zeus_change_card'])
24312                ) {
24313                    # check  if lite plan is new register
24314                    $isLitePlanNewRegister = isset($data['zeus_cred_card_register']) ? true : false; 
24315
24316                    $lptParams = [
24317                        'userId' => $userData['User']['id'],
24318                        'formType' => $form_type,
24319                        'isNewRegister' => $isLitePlanNewRegister,
24320                        'studentDiscountOptionData' => $discountOption
24321                    ];
24322
24323                    # create a lite plan payment transaction 
24324                    $litePlanPT = $this->createLitePlanTransaction($lptParams);
24325
24326                    if ($litePlanPT) {
24327                        $data['ZPaymentFullLogs']['paymentHash'] = $litePlanPT['payment_hash'];
24328                        $data['ZPaymentFullLogs']['money'] = $litePlanPT['payment_monthly_amount'];
24329                    }
24330                }
24331
24332            //- chocotto plan
24333            } elseif (
24334                isset($data['ZPaymentFullLogs']['payment_plan_type']) && 
24335                in_array(
24336                    $data['ZPaymentFullLogs']['payment_plan_type'],
24337                    [
24338                        Configure::read('register_plan_types.chocotto')
24339                    ]
24340                )
24341            ) {
24342                $form_type = isset($data['z_payment_form_type']) ? $data['z_payment_form_type'] : 0;
24343
24344                # no need to change the hash for retry and change form type
24345                if (
24346                    $form_type != Configure::read("payment_credit_retry") && 
24347                    (!isset($data['zeus_change_card']) || !$data['zeus_change_card'])
24348                ) {
24349                    # check  if chocotto plan is new register
24350                    $isChocottoPlanNewRegister = isset($data['zeus_cred_card_register']) ? true : false; 
24351
24352                    $chocottoParams = [
24353                        'userId' => $userData['User']['id'],
24354                        'formType' => $form_type,
24355                        'isNewRegister' => $isChocottoPlanNewRegister
24356                    ];
24357
24358                    # create a lite plan payment transaction 
24359                    $chocottoPlanPT = $this->createChocottoPlanTransaction($chocottoParams);
24360
24361                    if ($chocottoPlanPT) {
24362                        $data['ZPaymentFullLogs']['paymentHash'] = $chocottoPlanPT['payment_hash'];
24363                        $data['ZPaymentFullLogs']['money'] = $chocottoPlanPT['payment_monthly_amount'];
24364                    }
24365                }
24366
24367            // premium plan with annual discount option
24368            } elseif (isset($data['ZPaymentFullLogs']['payment_plan_type']) && $data['ZPaymentFullLogs']['payment_plan_type'] == Configure::read('register_plan_types.premium_with_annual_discount_option')) {
24369                // get annual discount plan data
24370                $annualDiscountOption = $this->DiscountOptionsPrice->getPaymentData(['currencyCode' => $userInfo->currency_code, 'discountOptionId' => Configure::read('discount_option.annual.plan_id')]);
24371
24372                // redirect to credit page if annual discount option does not exist or is not enabled
24373                if (!$annualDiscountOption) {
24374                    // - redirect to mypage 
24375                    return $this->redirect('/');
24376                }
24377
24378                if ($data['ZPaymentFullLogs']['money'] <= $annualDiscountOption['amount']) {
24379                    $data['ZPaymentFullLogs']['money'] = 0;
24380                } else {
24381                    $data['ZPaymentFullLogs']['money'] -= $annualDiscountOption['amount'];
24382                }
24383
24384                // set the default value for dosh_status
24385                $doshStatus = Configure::read('discount_option.dosh_status.monthly_discount');
24386
24387                // check if it came from card registeration form
24388                $isFromCardRegistration = isset($data['zeus_cred_card_register']) ? true : false;
24389                if($isFromCardRegistration) {
24390                    // update the dosh_status to subscription as it is still in the free trial period.
24391                    $doshStatus = Configure::read('discount_option.dosh_status.subscription');
24392                }
24393
24394                $annualDiscountOption += [
24395                    'dosh_event' => Configure::read('discount_option.dosh_event.annual_discount'),
24396                    'dosh_status' => $doshStatus,
24397                    'option_after_name' => 'Annual Discount Option',
24398                    'option_type' => 3,
24399                    'from3DSecure' => true
24400                ];
24401
24402                $this->PaymentTransaction->updatePaymentParams(array('paymentHash' => $data['ZPaymentFullLogs']['paymentHash'], 'updateData' => ['discountOption' => $annualDiscountOption]));
24403            }
24404            
24405            // NJ-32737 - apply coupon
24406            $couponData = $this->Session->read('apply_coupon_usage_data');
24407            if (
24408                isset($couponData['useCouponAmount']) && $couponData['useCouponAmount'] > 0 &&
24409                in_array($data['z_payment_form_type'], Configure::read('allow_coupon.settlement_form_type'))
24410            ) {
24411                if ($data['ZPaymentFullLogs']['money'] <= $couponData['useCouponAmount']) {
24412                    $data['ZPaymentFullLogs']['money'] = 0;
24413                } else {
24414                    $data['ZPaymentFullLogs']['money'] -= $couponData['useCouponAmount'];
24415                }
24416                $this->PaymentTransaction->updatePaymentParams(array(
24417                    'paymentHash' => $data['ZPaymentFullLogs']['paymentHash'], 
24418                    'updateData' => ['couponUseSettlement' => $couponData]
24419                ));
24420                
24421                $this->log($data['ZPaymentFullLogs'],'users_coupon');
24422            }
24423
24424            if ((!isset($data['zeus_change_card']) || !$data['zeus_change_card']) && (!isset($data['zeus_cred_card_register']) || !$data['zeus_cred_card_register'])) { 
24425                $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userData['User']['id']);
24426                $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userData['User']['id'], false, Configure::read('appreciation_data.payment_element_type') );
24427                $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userData['User']['id'], false, Configure::read('payment_element_type.live'));
24428
24429                //NJ-20741
24430                $memcache_receivable_data = $this->memcache->get('memcache_receivable_data' . $userData['User']['id']);
24431                $reservationCoinPrice = isset($memcache_receivable_data['receivable_reservation_data']['reservation_coin_price']) ? $memcache_receivable_data['receivable_reservation_data']['reservation_coin_price'] : 0;
24432                $individual_payment_card_empty = isset($memcache_receivable_data['receivable_reservation_data']['individual_payment_card_empty']) && $memcache_receivable_data['receivable_reservation_data']['individual_payment_card_empty'] == true;
24433
24434                // do not charge immediately if individual payment card is empty
24435                if ($individual_payment_card_empty == false) {
24436                    $receivablePayment += $reservationCoinPrice;
24437                }
24438
24439                // validate the value if it is numeric
24440                $data['ZPaymentFullLogs']['money'] = isset($data['ZPaymentFullLogs']['money']) && is_numeric($data['ZPaymentFullLogs']['money']) ? $data['ZPaymentFullLogs']['money'] : 0;
24441                $receivablePayment = is_numeric($receivablePayment) ? $receivablePayment : 0;
24442                $appreciationReceivable = is_numeric($appreciationReceivable) ? $appreciationReceivable : 0;
24443                $liveLessonReceivable = is_numeric($liveLessonReceivable) ? $liveLessonReceivable : 0;
24444                
24445                // monthly settlement + payment receivables
24446                $data['ZPaymentFullLogs']['money'] = $data['ZPaymentFullLogs']['money'] + $receivablePayment + $appreciationReceivable + $liveLessonReceivable;
24447            }
24448
24449            if (isset($data['zeus_change_card']) && $data['zeus_change_card']) { 
24450                $data['no_redirection'] = true;
24451                // get reserve payment receivable
24452                $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userData['User']['id']);
24453
24454                // get appreciation payment receivable
24455                $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userData['User']['id'], false, Configure::read('appreciation_data.payment_element_type'));
24456
24457                // get live lesson payment receivable
24458                $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userData['User']['id'], false, Configure::read('payment_element_type.live'));
24459
24460                // payment receivables added
24461                $data['ZPaymentFullLogs']['money'] = $receivablePayment + $appreciationReceivable + $liveLessonReceivable;
24462            
24463                //- create new transaction if has payment receivable
24464                if (
24465                    !empty($data['ZPaymentFullLogs']['money']) &&
24466                    $data['ZPaymentFullLogs']['money'] > 0
24467                ) {
24468                    //-update amount
24469                    $userData['User']['paymentAmount'] = $data['ZPaymentFullLogs']['money'];
24470
24471                    // flagging for updating corporate user receivables
24472                    if (isset($userData['User']['corporate_id']) && $userData['User']['corporate_id']) {
24473                        $userData['User']['updateCorporateReceivable'] = true;
24474                    }
24475
24476                    if ($pt = $this->createPaymentTransaction(Configure::read('payment_credit_change'), $userData['User'])) {
24477                        //-update payment hash
24478                        $data['ZPaymentFullLogs']['paymentHash'] = $pt['payment_hash'];
24479                    }
24480                }
24481            }
24482
24483            $paymentHash = isset($data["ZPaymentFullLogs"]['paymentHash']) ? $data["ZPaymentFullLogs"]['paymentHash'] : '';
24484
24485            // If event is credit retry/force settlement check if discounted
24486            if (isset($data['z_payment_form_type']) && in_array($data['z_payment_form_type'], array(
24487                Configure::read('payment_credit_retry'), 
24488                Configure::read('payment_credit_force_charge'))
24489            )) {
24490
24491                $updateData = array();
24492
24493                if ($data['z_payment_form_type'] == Configure::read('payment_credit_retry')) {
24494                    // get user active annual discount option
24495                    $annualDiscountOptionData = $this->UserDiscountOptionsTerm->getTerm([
24496                        'user_id' => $userInfo->id,
24497                        'discount_option_id' => Configure::read('discount_option.annual.plan_id'),
24498                        'status' => 1
24499                    ]);
24500
24501                    if ($annualDiscountOptionData) {
24502                        if ($annualDiscountOptionData['amount'] < $data['ZPaymentFullLogs']['money']) {
24503                            $data['ZPaymentFullLogs']['money'] -= $annualDiscountOptionData['amount'];
24504                        } else {
24505                            $data['ZPaymentFullLogs']['money'] = 0;
24506                        }
24507                    }
24508
24509                    $coupon = $this->UsersCouponV1->getCouponUseRequest(array(
24510                        'userId' => $userData['User']['id'],
24511                        'kbn' => Configure::read('coupon_kbn.monthly_settlement')
24512                    ));
24513
24514                    if ($coupon) {
24515                        $data['ZPaymentFullLogs']['money'] -= $coupon['amount'];
24516                        $updateData['monthlyDiscount'] = $coupon['amount'];
24517                        $updateData['discounted_amount'] = $coupon['amount'];
24518                        $updateData['monthly_grp_id'] =  $coupon['grp_id'];
24519                    }
24520                }
24521
24522                // NJ-58167: Updates the amount in payment_params to properly set data in payment details for retry/force charge.
24523                $updateData['paymentAmount'] = isset($data['ZPaymentFullLogs']['money']) ? (int)$data['ZPaymentFullLogs']['money'] : 0;
24524                $this->PaymentTransaction->updatePaymentParams([
24525                    'paymentHash' => $paymentHash, 
24526                    'updateData' => $updateData
24527                ]);
24528                
24529                // If 0 payment no kickback 
24530                // if ($data['ZPaymentFullLogs']['money'] <= 0) {
24531                //     $zeroPaymentParams = array(
24532                //         'paymentHash' => $data["ZPaymentFullLogs"]['paymentHash'],
24533                //         'userId' => $userData['User']['id'],
24534                //         'money' => $data['ZPaymentFullLogs']['money'],
24535                //         'cardCompany' => Configure::read('card_company.zeus'),
24536                //         'controllerName' => 'Payment',
24537                //         'actionName' => 'zeuspayGetChallenge',
24538                //         'logFileName' => 'card_retry'
24539                //     );
24540
24541                //     if ($data['z_payment_form_type'] == Configure::read('payment_credit_force_charge')) {
24542                //         $discountedAmount = isset($couponData['useCouponAmount']) ? $couponData['useCouponAmount'] : 0;
24543                //         // create new term for force charge
24544                //         if (isset($annualDiscountOption) && $annualDiscountOption) {
24545                //             $udotData = [
24546                //                 'userId' => $userData['User']['id'],
24547                //                 'discountOptionId' => $annualDiscountOption['discount_option_id'],
24548                //                 'discountOptionPriceId' => $annualDiscountOption['discount_option_price_id'],
24549                //                 'contractStart' => date('Y-m-d 00:00:00'),
24550                //                 'logFileName' => 'card_retry'
24551                //             ];
24552
24553                //             $zeroPaymentParams['zeroPayment3D'] = true;
24554
24555                //             // create user discount option term
24556                //             $this->UserDiscountOptionsTerm->createTerm($udotData);
24557
24558                //             // get newly created term
24559                //             $annualDiscountOptionData = $this->UserDiscountOptionsTerm->getTerm([
24560                //                 'user_id' => $userData['User']['id'],
24561                //                 'discount_option_id' => Configure::read('discount_option.annual.plan_id'),
24562                //                 'status' => 1
24563                //             ]);
24564
24565                //             // append discount term to payment transactions
24566                //             if ($annualDiscountOptionData) {
24567                //                 $annualDiscountOption += [
24568                //                     'user_id' => $userData['User']['id'],
24569                //                     'discount_option_term_id' => $annualDiscountOptionData['discount_option_term_id']
24570                //                 ];
24571                //                 $this->PaymentTransaction->updatePaymentParams(array('paymentHash' => $data['ZPaymentFullLogs']['paymentHash'], 'updateData' => ['discountOption' => $annualDiscountOption, 'discounted_amount' => $discountedAmount]));
24572                //             }
24573                //         } else {
24574                //             // append discounted amount
24575                //             $this->PaymentTransaction->updatePaymentParams(array('paymentHash' => $data['ZPaymentFullLogs']['paymentHash'], 'updateData' => ['discounted_amount' => $discountedAmount]));
24576                //         }
24577                //     }
24578
24579                //     $zeroPayment = $this->Payment->zeroPayment($zeroPaymentParams);
24580
24581                //     $xmlResponse = array();
24582
24583                //     if (isset($zeroPayment['success']) && $zeroPayment['success']) {
24584                //         // update old complimentary code active_flg to 0
24585                //         if($userData['User']['complimentary_code']){
24586                //             $this->CompCodeUsage->updateAll(
24587                //                 array (
24588                //                     'active_flg' => 0
24589                //                 ),
24590                //                 array ('user_id' => $userData['User']['id'],
24591                //                         'active_flg' => 1,
24592                //                         'code' => $userData['User']['complimentary_code'])
24593                //             );
24594                //         }
24595
24596                //         $xmlResponse['result']['status'] = 'success';
24597                //         $xmlResponse['zero_payment'] = true;
24598                //         $xmlResponse['challenge_status'] = 1;
24599                //         $xmlResponse['paymentHash'] = $data["ZPaymentFullLogs"]['paymentHash'];
24600                //         $xmlResponse['paymentAmount'] = $data['ZPaymentFullLogs']['money'];
24601                //     }
24602
24603                //     return json_encode($xmlResponse);
24604                // }
24605            }
24606
24607            $paymentHash = isset($data["ZPaymentFullLogs"]['paymentHash']) ? $data["ZPaymentFullLogs"]['paymentHash'] : '';
24608
24609            if (
24610                (!empty($data['zeus_cred_card_register']) && $data['zeus_cred_card_register'] == 1) || 
24611                (!empty($data['zeus_change_card']) && $data['zeus_change_card'] == 1)
24612            ) {
24613                if (empty($data['zeus_token_card_name'])) {
24614                    $this->log(__LINE__, __METHOD__, 'Cardholder Name is not present --> ' . json_encode($data), 'debug');
24615                    $this->Session->setFlash('Cardholder Name is not present', array("element" => "flashfail"));
24616                }
24617            
24618                if (empty($userData['User']['email'])) {
24619                    $this->log(__LINE__, __METHOD__, 'Email is not present --> ' . json_encode($data), 'debug');
24620                    $this->Session->setFlash('Email is not present', array("element" => "flashfail"));
24621                }
24622            }
24623
24624            if ($paymentHash) {
24625                // If retry is already on process don't allowed to process again until 1 min
24626                if ($this->memcache->get('zeus_credit_retry'.$paymentHash)) {
24627                    $xmlResponse = array('challenge_status' => 3);
24628                    return json_encode($xmlResponse);
24629                }
24630
24631                $this->memcache->set(array(
24632                    'key' => 'zeus_credit_retry'.$paymentHash,
24633                    'value' => true,
24634                    'expire' => 60 // 1 min
24635                ));
24636            }
24637
24638            $pData = array(
24639                'clientIp' => Configure::read('ZEUS_clientip'), # client ip
24640                'cardNumber' => $data['zeus_token_card_number'], # card number
24641                'expyy' => !empty($data['zeus_token_card_expires_year']) ? $data['zeus_token_card_expires_year'] : "0", # expired year
24642                'expmm' => !empty($data['zeus_token_card_expires_month']) ? $data['zeus_token_card_expires_month'] : "0", # expired month
24643                'telNo' => Configure::read('credit.default_telno'), # telephone number
24644                'email' => $userData['User']['email'], # email
24645                'username' => $data['zeus_token_card_name'], # username
24646                'phoneNumber' => !empty($userData['User']['phone_number']) ? $userData['User']['phone_number'] : null,
24647                'countryCode' => !empty($userCountryCode['CountryCode']['num']) ? $userCountryCode['CountryCode']['num'] : null,
24648                'sendId' => $userData['User']['id'], # id
24649                'money' => isset($data['ZPaymentFullLogs']['money']) ? (int)$data['ZPaymentFullLogs']['money'] : 0, # money
24650                'tokenKey' => $data["ZPaymentFullLogs"]['zeusTokenValue'],
24651                'paymentHash' => $data["ZPaymentFullLogs"]['paymentHash']
24652            );
24653
24654            $rUserId = $userData['User']['id'];            
24655        }
24656
24657        $moneyAmout = isset($data['ZPaymentFullLogs']['money']) ? (int)$data['ZPaymentFullLogs']['money'] : 0;
24658        
24659        // overwrite for study abroad; special payment
24660        if ($studyAbroadFlg) {
24661            $pData['money'] = $originalAmount;
24662        }
24663
24664        App::import('Helper', 'Xml');
24665
24666        // - validate user
24667        $checkUser = $this->checkUser(null, null, true);
24668        if(
24669            // - if paid user
24670            $checkUser == Configure::read('user.member_type_paid') &&
24671            
24672            // - if has money
24673            $moneyAmout != 0 &&
24674            
24675            // - if not a complimentary user
24676            !($userData['User']['complimentary_code']) && 
24677
24678            // don't do redirection event
24679            empty($data['no_redirection'])
24680        ) {
24681            $form_type = isset($data['z_payment_form_type']) ? $data['z_payment_form_type'] : 0;
24682            // - redirect to complete page
24683            return $this->processRedirection($form_type);
24684        }
24685        
24686        // - set response
24687        $response = $this->ZCharge->create_charge_challenge(($pData));
24688        $xmlArray = Xml::toArray(Xml::build($response));
24689        $xmlResponse = isset($xmlArray['response']) ? $xmlArray['response'] : array();
24690
24691        $tmpPData = $pData;
24692        
24693        // - send debugging data
24694        unset($tmpPData['clientIp']);
24695        unset($tmpPData['cardNumber']);
24696        unset($tmpPData['email']);
24697        unset($tmpPData['expyy']);
24698        unset($tmpPData['expmm']);
24699        unset($tmpPData['phoneNumber']);
24700        if (isset($data["ZPaymentFullLogs"]['paymentHash']) && $data["ZPaymentFullLogs"]['paymentHash']) {
24701            $this->sendZeusResponseSlackMessage(array(
24702                'paymentHash' => $data["ZPaymentFullLogs"]['paymentHash'],
24703                'response' => $response,
24704                'userId' => !empty($corporateId) ? $corporateId : $userData['User']['id'],
24705                'userToken' => $userData['User']['api_token'],
24706                'action' => 'generating_zcharge_challenge -> ' . json_encode($tmpPData)
24707            ));
24708        }
24709
24710        // NJ-28462
24711        if( $data['corpIndiUser'] ) {
24712            $xmlResponse['paymentHash'] = $corpIndiPT['paymentHash'];
24713            $xmlResponse['paymentAmount'] = $corpIndiPT['paymentAmount'];
24714        }
24715
24716        // - add payment amount -> base on money that send to zeus
24717        if (!isset($xmlResponse['paymentAmount']) && isset($pData['money']) && $pData['money']) {
24718            $xmlResponse['paymentAmount'] = $pData['money'];
24719        }
24720
24721        // - ensure payment hash
24722        if (!isset($xmlResponse['paymentHash']) && isset($pData['paymentHash']) && $pData['paymentHash']) {
24723            $xmlResponse['paymentHash'] = $pData['paymentHash'];
24724        }
24725
24726        // if corporate
24727        if (!empty($corporateId)) {
24728            $xmlResponse['corporateId'] = $corporateId;
24729        }
24730
24731        // set zeus challenge flag
24732        if (isset($xmlResponse['result']['status']) && $xmlResponse['result']['status'] == 'success') {
24733            $userId = !empty($corporateId) ? $corporateId : $userData['User']['id'];
24734            
24735            // update old complimentary code active_flg to 0
24736            if($userData['User']['complimentary_code']){
24737                $this->CompCodeUsage->updateAll(
24738                    array (
24739                        'active_flg' => 0
24740                    ),
24741                    array ('user_id' => $userData['User']['id'],
24742                            'active_flg' => 1,
24743                            'code' => $userData['User']['complimentary_code'])
24744                );
24745            }
24746
24747            // - set flag
24748            $this->memcache->set(array(
24749                'key' => 'zeus3DSecureChallengeFlg_'.$userData['User']['id'],
24750                'value' => true,
24751                'expire' => 1800 // 30 minutes
24752            ));
24753            
24754            // - set 3ds formType
24755            $this->memcache->set(array(
24756                'key' => 'zeus_3dSecure_challenge_formType_'.$userData['User']['id'],
24757                'value' => isset($data['z_payment_form_type']) ? $data['z_payment_form_type'] : 0,
24758                'expire' => 1800 // 30 minutes
24759            ));
24760            
24761            // - set data
24762            $test = $this->memcache->set(array(
24763                'key' => 'zeus_3d_secure_pt_'.$userData['User']['id'],
24764                'value' => ($pData),
24765                'expire' => 1800 // 30 minutes
24766            ));
24767
24768            $this->memcache->set(array(
24769                'key' => 'register_or_charge_card_' . $userData['User']['id'],
24770                'value' => true,
24771                'expire' => 3600 // 1 hour
24772            ));
24773
24774            if (isset($data['fromPage']) && !empty($data['fromPage'])) {
24775                switch ($data['fromPage']) {
24776                    case 'coin':
24777                        $this->memcache->set(array(
24778                            'key' => 'common_corporate_transaction_coin_' . $userData['User']['id'],
24779                            'value' => true,
24780                            'expire' => 3600 // 1 hour
24781                        ));
24782                        break;
24783                    default:
24784                        $this->memcache->set(array(
24785                            'key' => 'common_corporate_transaction_' . $userData['User']['id'],
24786                            'value' => true,
24787                            'expire' => 3600 // 1 hour
24788                        ));
24789                        break;
24790                }
24791            }
24792        }
24793
24794        // // - debug
24795        // if (
24796        //     isset($xmlResponse["result"]["status"]) &&
24797        //     $xmlResponse["result"]["status"] == "success" &&
24798        //     (
24799        //         (
24800        //             Configure::read('ENVIRONMENT') == 'PRODUCTION' && 
24801        //             $data['zeus_token_card_number'] == '4834421406393969'
24802        //         )
24803        //         ||
24804        //         (
24805        //             Configure::read('ENVIRONMENT') == 'DEV' ||
24806        //             Configure::read('ENVIRONMENT') == 'STAGING'
24807        //         )
24808        //     )
24809        // ) {
24810        //     // - send slack
24811        //     $mySlack = new mySlack();
24812        //     $mySlack->channel = myTools::checkChannel("#fdci-nativecamp", "#fdci-nativecamp");
24813        //     $mySlack->link_names = true;
24814        //     $mySlack->allow_test_channel = true;
24815        //     $mySlack->token = "xoxp-392902820692-393103987059-747628176676-c8ea0bf485312302ce3788cc55100b30";
24816        //     $mySlack->text = "<!subteam^SNX2TCYAE|fdci-delivery>";
24817        //     $mySlack->text .= "```";
24818        //     $mySlack->text .= "environment: " . json_encode(Configure::read('ENVIRONMENT')) ."\n\n";
24819        //     $mySlack->text .= "user_id: " . json_encode($rUserId) ."\n\n";
24820        //     $mySlack->text .= "amount: " . json_encode($moneyAmout);
24821        //     $mySlack->text .= "```";
24822        //     $mySlack->sendSlack();
24823        // }
24824        
24825        // - return response
24826        return json_encode($xmlResponse);
24827    }
24828
24829    public function reportZeusChallengeResponse($data = array()) {
24830        $this->autoRender = false;
24831        $postData = $data ? $data : $this->request->data;
24832        $getData = $this->request->query;
24833        $userId = isset($getData['userID']) && !empty($getData['userID']) ? $getData['userID'] : $this->Session->read('register_user_id');
24834        $userToken = isset($getData['userApiToken']) ? $getData['userApiToken'] : '';
24835
24836        // - if invalid
24837        if (isset($postData['status']) && $postData['status'] != 'success' && isset($postData['PaRes']) && $postData['PaRes'] == 'N') {
24838            $this->log(__METHOD__ . ' PaRes failure: ' . $userId . ' | ' . $userToken . ' Data: ' . json_encode($postData), 'debug');
24839            return array(
24840                'success' => false,
24841                'errorMsg' => 'PaRes failure'
24842            );
24843        }
24844
24845        // - get user data
24846        $userData = $this->User->getUserDataUsingMasterDb(
24847            'first',
24848            array('User.id' => $userId),
24849            array(
24850                'User.email', 'User.id', 'User.corporate_id'
24851            )
24852        );
24853
24854        // - check mobapp token
24855        if (empty($userData) && !empty($userToken)){
24856            $userData = $this->User->getUserDataUsingMasterDb(
24857                'first',
24858                array('User.api_token' => $userToken),
24859                array(
24860                    'User.email', 'User.id', 'User.corporate_id'
24861                )
24862            );
24863        }
24864
24865        // - get userID
24866        $userId = isset($userData['User']['id']) ? $userData['User']['id'] : $userId;
24867
24868        // - get company data
24869        $corporateId = $this->Session->read('corporateCompanyID') ? $this->Session->read('corporateCompanyID') : ( !empty($getData['corporateId']) ? $getData['corporateId'] : '' );
24870        $corporateData = array();
24871        if (!empty($corporateId)){
24872            $corporateData = $this->Corporate->find("first",array(
24873                    "conditions" => array( "Corporate.id" => $corporateId),
24874                    "fields" => array("Corporate.email","Corporate.name"),
24875                    "recursive" => -1,
24876                )
24877            );
24878            $userId = $corporateId;
24879        }
24880
24881        // - if userID doe snot exist, return false
24882        if (!$userId) {
24883            $postData['PaRes'] = "N";
24884            echo json_encode($postData);
24885            $this->sendZeusResponseSlackMessage(array(
24886                'paymentHash' => @$getData['paymentHash'],
24887                'response' => "invalid user id supplied",
24888                'userId' => @$userId,
24889                'userToken' => $userToken,
24890                'action' => 'failed_to_get_user_information -> ' . json_encode($userId)
24891            ));
24892            return array(
24893                'success' => false,
24894                'errorMsg' => 'Invalid User Id supplied'
24895            );
24896        }
24897
24898        // - get paymentHash
24899        $paymentHash = "";
24900        if (isset($getData['paymentHash']) && $getData['paymentHash']) {
24901            $paymentHash = $getData['paymentHash'];
24902
24903        } else {
24904            $paymentHash = $this->memcache->get('zeus_3d_secure_pt_'.$userId);
24905            $getData['paymentHash'] = $paymentHash["paymentHash"];
24906
24907        }
24908
24909        // - if userID doe snot exist, return false
24910        if (!$paymentHash) {
24911            $postData['PaRes'] = "N";
24912            echo json_encode($postData);
24913            $this->sendZeusResponseSlackMessage(array(
24914                'paymentHash' => @$getData['paymentHash'],
24915                'response' => "invalid paymenthash supplied",
24916                'userId' => $userId,
24917                'userToken' => $userToken,
24918                'action' => 'no_payment_hash_provided'
24919            ));
24920            return array(
24921                'success' => false,
24922                'errorMsg' => 'Invalid Payment Hash supplied'
24923            );
24924        }
24925
24926        // - check if money amount  not exist
24927        if(!isset($getData['money']) || empty($getData['money'])) {
24928            $this->PaymentTransaction->openDBReplica();
24929            $getPtrans = $this->PaymentTransaction->find('first', array(
24930                'fields' => array('payment_params'),
24931                'conditions' => array('payment_hash' => $paymentHash),
24932                'recursive' => -1
24933            ));
24934            $this->PaymentTransaction->closeDBReplica();
24935
24936            // - if transaction does not exist
24937            if (!$getPtrans) {
24938                if (!empty($getData['corporateId'])) {
24939                    return true; // return true if corporate 
24940                }
24941                $postData['PaRes'] = "N";
24942                echo json_encode($postData);
24943                $this->sendZeusResponseSlackMessage(array(
24944                    'paymentHash' => @$getData['paymentHash'],
24945                    'response' => "no transaction found!",
24946                    'userId' => $userId,
24947                    'userToken' => $userToken,
24948                    'action' => 'failed_to_getPayment_transaction -> ' . json_encode($paymentHash)
24949                ));
24950                return array(
24951                    'success' => false,
24952                    'errorMsg' => 'No transaction found'
24953                );
24954            }
24955        }
24956        
24957        // - get transaction
24958        if (isset($getPtrans['PaymentTransaction']['payment_params'])) {
24959            $parseData = json_decode($getPtrans['PaymentTransaction']['payment_params'], true);
24960            $getData['money'] = $parseData['paymentAmount'];
24961        }
24962
24963        // - set response
24964        $response2 = $this->ZCharge->auth_charge_request([
24965            "auth_status" => $postData["MD"],
24966            "auth_code" => $postData["PaRes"]
24967        ]);
24968        $this->sendZeusResponseSlackMessage(array(
24969            'paymentHash' => $getData['paymentHash'],
24970            'response' => $response2,
24971            'userId' => $userId,
24972            'userToken' => $userToken,
24973            'action' => 'failed_to_authenticate_charged_request -> ' . json_encode($postData)
24974        ));
24975
24976        // - set response
24977        $response = $this->ZCharge->pay_charge_request([
24978            "auth_xid" => $postData["MD"]
24979        ]);
24980
24981        // - send slack message
24982        $slackMessageParams = array(
24983            'paymentHash' => $getData['paymentHash'],
24984            'response' => $response,
24985            'userId' => $userId,
24986            'userToken' => $userToken,
24987            'action' => 'failed_to_pay_charge_request -> ' . json_encode($getData)
24988        );
24989
24990        if (isset($response['payment_has_curl_error'])) {
24991            $slackMessageParams['error_msg'] = $response['payment_has_curl_error'];
24992            unset($response['payment_has_curl_error']);
24993            $slackMessageParams['response'] = json_encode($response);
24994        }
24995
24996        $this->sendZeusResponseSlackMessage($slackMessageParams);
24997
24998        if(empty($response) || !$response) {
24999            $response = array();
25000        }
25001        
25002        $xmlArray = Xml::toArray(Xml::build($response));
25003        $res = isset($xmlArray['response']) ? $xmlArray['response'] : array();
25004        $sendPoint = isset($res['addition_value']['sendpoint']) ? $res['addition_value']['sendpoint'] : '';
25005
25006        $zeuspay = array(
25007            'result' => isset($res['result']['status']) && $res['result']['status'] == 'success' ? 'OK' : 'NG',
25008            'money' => isset($getData['money']) && !empty($getData['money']) ? $getData['money'] : 0,
25009            'sendid' => isset($res['addition_value']['sendid']) && !empty($res['addition_value']['sendid']) ? $res['addition_value']['sendid'] : $userId,
25010            'sendpoint' => $sendPoint,
25011            'clientip' => Configure::read('ZEUS_clientip'),
25012            'ordd' => isset($res['order_number']) ? $res['order_number'] : '',
25013            'email' =>isset($corporateData['Corporate']['email']) ? $corporateData['Corporate']['email'] : $userData['User']['email'],
25014            'telno' => Configure::read('credit.default_telno'),
25015            'cardnumber' => isset($res['card']['number']['suffix']) ? $res['card']['number']['suffix'] : '',
25016            'cardbrand' => isset($res['addition_value']['ctype']) ? $res['addition_value']['ctype'] : '',
25017            'zeus3DSecureFlg' => 1
25018        );
25019        $tmpZeuspay = $zeuspay;
25020
25021        // - start debugging
25022        unset($tmpZeuspay['telno']);
25023        unset($tmpZeuspay['clientip']);
25024        unset($tmpZeuspay['email']);
25025        unset($tmpZeuspay['cardnumber']);
25026        $this->sendZeusResponseSlackMessage(array(
25027            'paymentHash' => $getData['paymentHash'],
25028            'response' => json_encode($zeuspay),
25029            'userId' => $userId,
25030            'userToken' => $userToken,
25031            'action' => 'triggering zeuspayments -> ' . json_encode($tmpZeuspay)
25032        ));
25033
25034        // NJ-20741
25035        if (
25036            isset($postData['PaRes']) && $postData['PaRes'] == "Y" && 
25037            isset($res['result']['status']) &&
25038            !empty($getData['zeusFormType']) &&
25039            ($getData['zeusFormType'] == 'corp_user_change_personal_card' || $getData['zeusFormType'] == 'student_discount_user_change_personal_card' || $getData['zeusFormType'] == 'common_corporate_card') &&
25040            !empty($getData['fromPC']) && $getData['fromPC'] == 1
25041        ) {
25042            $memcache_receivable_data = $this->memcache->get('memcache_receivable_data' . $userId);
25043            $reservationCoin = isset($memcache_receivable_data['receivable_reservation_data']['reservation_coin']) ? $memcache_receivable_data['receivable_reservation_data']['reservation_coin'] : 0;
25044            
25045            if (isset($res['result']['status']) && $res['result']['status'] == 'success') {
25046                $memcache_receivable_data['payment_status'] = 1;
25047                $reservationCoinPrice = isset($memcache_receivable_data['receivable_reservation_data']['reservation_coin_price']) ? $memcache_receivable_data['receivable_reservation_data']['reservation_coin_price'] : 0;
25048                
25049                if ((int)$reservationCoinPrice > 0) {
25050                    if (!isset($memcache_receivable_data)) $memcache_receivable_data = [];
25051                    $memcache_receivable_data['receivable_reservation'] = 1;
25052                    $memcache_receivable_data['paying_receivables'] = 1;
25053
25054                    $reserveData = isset($memcache_receivable_data['reserve_data']) ? $memcache_receivable_data['reserve_data'] : [];
25055                    if (!empty($reserveData)) {
25056
25057                        $reserveData['paying_receivables'] = 1;
25058                        $reserveData['card_company'] = Configure::read('card_company.zeus');
25059                        if (isset($memcache_receivable_data['actionType']) && $memcache_receivable_data['actionType'] == 'lesson_reservation') {
25060                            try {
25061                                $reserve_response = $this->LessonSchedule->addReserve($reserveData);
25062                            } catch (\Exception $e) {
25063                                $this->LessonSchedule->sendSlackExceptionReport([
25064                                    'error_message' => $e->getMessage(),
25065                                    'reserve_data' => $reserveData
25066                                ]);
25067                            }
25068                        } else if (isset($memcache_receivable_data['actionType']) && $memcache_receivable_data['actionType'] == 'reserved_confirmation') {
25069                            $reserve_response = $this->LessonSchedule->confirmReservationSchedule($reserveData);
25070                        }
25071
25072                        $memcache_receivable_data['reserve_response'] = isset($reserve_response) ? $reserve_response : null;
25073
25074                        if (
25075                            isset($reserve_response['lessonSchedId']) && $reserve_response['lessonSchedId'] > 0 &&
25076                            isset($reserve_response['res']) && $reserve_response['res'] == 1
25077                        ) {
25078                            $memcache_receivable_data['add_reserve_response'] = 1;
25079                            $memcache_receivable_data['lessonSchedId'] = $reserve_response['lessonSchedId'];
25080                        } else if (isset($reserve_response) && $reserve_response == '-1') {
25081                            $memcache_receivable_data['add_reserve_response'] = -1;
25082
25083                            if ($reservationCoin > 0) {
25084                                $_pointParams = array(
25085                                    'userId' => $userId,
25086                                    'point' => $reservationCoin,
25087                                    'kbn' => 2, // return coin
25088                                    'kbnType' => 1, // add coin
25089                                    'coinType' => 2, // // service coin
25090                                    'coinFailMessage' => Configure::read('coin.failed.reservation')
25091                                );
25092    
25093                                $this->UsersPoint->performPointTransaction($_pointParams);
25094                            }
25095                        }
25096
25097                        $individual_payment_card_empty = isset($memcache_receivable_data['receivable_reservation_data']['individual_payment_card_empty']) && $memcache_receivable_data['receivable_reservation_data']['individual_payment_card_empty'] == true;
25098                    }
25099                }
25100            } else {
25101                $memcache_receivable_data['paying_receivables'] = 1;
25102                $memcache_receivable_data['payment_status'] = 0;
25103            }
25104            
25105
25106            if (!empty($memcache_receivable_data)) {
25107                $this->memcache->set([
25108                    'key' => 'memcache_receivable_data' . $userId,
25109                    'value' => $memcache_receivable_data, 
25110                    'expire' => 1800 // 30 minutes
25111                ]);
25112            }
25113        }
25114        // end NJ-20741
25115
25116        // set zeus challenge paymenr result
25117        $this->memcache->set(array(
25118            'key' => 'zeus3DSecurePaymentSuccessFlg_' . $userId,
25119            'value' => $zeuspay['result'],
25120            'expire' => 1800 // 30 minutes
25121        ));
25122        
25123        $url = myTools::getUrl() . '/payment/zeuspay?'.http_build_query($zeuspay);
25124        $ch = curl_init($url);
25125        curl_setopt($ch, CURLOPT_URL, $url);
25126        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
25127        curl_setopt($ch, CURLOPT_HEADER,         false);
25128        curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36');
25129        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
25130        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
25131        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
25132        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
25133        $result = curl_exec($ch);
25134        curl_close($ch);
25135
25136        $this->Session->write('register_user_id', $userId);
25137            
25138        // - add response
25139        $tmpZeusPay = $zeuspay;
25140        unset($tmpZeuspay['email']);
25141        unset($tmpZeuspay['cardnumber']);
25142        unset($tmpZeuspay['telno']);
25143        $mySlack = new mySlack();
25144        $mySlack->allow_test_channel = true;
25145        $mySlack->channel = myTools::checkChannel("#nc-zeus-3ds-result", "#nc-zeus-3ds-result");
25146        $mySlack->username = "ZEUS CHALLENGE PARES RESPONSE";
25147        $mySlack->link_names = true;
25148        $mySlack->token = "xoxb-392902820692-6499139810404-RHHGc6Z5ZB9o2KkiGhzTTtlQ";
25149        $mySlack->text = "```";
25150        $mySlack->text .= "user_id || corporate id || token: " . json_encode($userId) ." OR " . $userToken . "\n\n";
25151        $mySlack->text .= "post_data: " . json_encode($postData) ."\n\n";
25152        $mySlack->text .= "get_data: " . json_encode($getData) ."\n\n";
25153        $mySlack->text .= "auth_response: " . json_encode($response2) ."\n\n";
25154        $mySlack->text .= "pay_response: " . json_encode($response) ."\n\n";
25155        $mySlack->text .= "zeuspay params: " . json_encode($tmpZeuspay) ."\n\n";
25156        $mySlack->text .= "zeuspay response: " . json_encode($result) ."\n\n";
25157        $mySlack->text .= "referrer: " . json_encode($_SERVER['HTTP_REFERER']) ."\n\n";
25158        $mySlack->text .= "user agent: " . json_encode(myTools::uAPlatformVersion($_SERVER['HTTP_USER_AGENT'])) ."\n\n";
25159        $mySlack->text .= "```";
25160        
25161        // - send slack
25162        if (!$mySlack->postMessage()) {
25163        }
25164
25165        if (!empty($memcache_receivable_data) && isset($memcache_receivable_data['receivable_reservation_data']['reservation_coin_price'])) {
25166            return array(
25167                'success' =>true,
25168                'memcache_receivable_data' => $memcache_receivable_data,
25169                'errorMsg' => ''
25170            );
25171        }
25172
25173        // - if zeuspay result is NG
25174        if ($zeuspay['result'] == 'NG' && !empty($userData['User']['corporate_id'])) {
25175            return array(
25176                'success' => false,
25177                'errorMsg' => 'NG_return from zeus'
25178            );
25179        }
25180        
25181        // - return
25182        return true;
25183    }
25184
25185    private function sendZeusResponseSlackMessage($params) {
25186        // - add response
25187        $mySlack = new mySlack();
25188        $mySlack->allow_test_channel = true;
25189        $mySlack->channel = myTools::checkChannel("#nc-zeus-3ds-result", "#nc-zeus-3ds-result");
25190        $mySlack->username = "ZEUS CHALLENGE RESPONSE";
25191        $mySlack->link_names = true;
25192        $mySlack->token = "xoxb-392902820692-6499139810404-RHHGc6Z5ZB9o2KkiGhzTTtlQ";
25193        $mySlack->text = "```";
25194        $mySlack->text .= "user_id || corporate id || token: " . $params['userId'] ." OR " . $params['userToken'] . "\n\n";
25195        $mySlack->text .= "payment_hash: " . $params['paymentHash'] ."\n\n";
25196        // $mySlack->text .= "response: " . $params['response'] ."\n\n";
25197        $mySlack->text .= "action: " . $params['action'] ."\n\n";
25198        if(isset($params['error_msg']) && $params['error_msg']) {
25199            $mySlack->text .= "error: " . $params['error_msg'] ."\n\n";
25200        }
25201        $mySlack->text .= "```";
25202        $mySlack->postMessage();
25203    }
25204    /**
25205     * @api {post} /payment/processRedirection/:form_type processRedirection()
25206     * @apiName processRedirection
25207     * @apiGroup Payment
25208     * @apiDescription Redirect to the correct page after payment
25209     * 
25210     * @apiParam {String} form_type Form type. Null if not set.
25211     * 
25212     * @apiSuccess {View} Redirect to the correct page after payment
25213     * 
25214     * @apiError {View} Redirect to the home page
25215     * 
25216     * @apiSuccessExample Success Response:
25217     * Redirects to {{ENV}}/payment/payment_credit_charge_complete if form_type is 'payment_credit_force_charge'
25218     * 
25219     * @apiSuccessExample Success Response:
25220     * Redirects to {{ENV}}/payment/payment_credit_retry_complete if form_type is 'payment_credit_retry'
25221     * 
25222     * @apiErrorExample Success Response:
25223     * Redirects to {{ENV}}/ if form_type is not set
25224     * 
25225     * @apiSampleRequest off
25226     */
25227    public function processRedirection($form_type = null) {
25228        if ($form_type == Configure::read('payment_credit_force_charge')) {
25229            return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_charge_complete'));
25230
25231        } else if ($form_type == Configure::read('payment_credit_retry')) {
25232            return $this->redirect(array('controller' => 'payment', 'action' => 'payment_credit_retry_complete'));
25233
25234        } else {
25235            return $this->redirect(myTools::getUrl() . '/');
25236        }
25237    }
25238
25239    /**
25240     * Aftee: prepare payment form data
25241     * Create new payment transaction
25242     * get cpayment data and checksum
25243     */
25244    public function getAfteeHostedPage() {
25245        $this->layout = '';
25246
25247        if ($this->request->is('post')) {
25248            $postData = $this->request->data;
25249
25250            // throw exception if there is/are missing parameter(s)
25251            if (
25252                !isset($postData['logFileName']) ||
25253                !isset($postData['apiToken']) ||
25254                !isset($postData['formType']) ||
25255                !isset($postData['successUrl']) ||
25256                !isset($postData['paymentMethodType']) ||
25257                !isset($postData['memKeyError']) ||
25258                !isset($postData['referrer']) ||
25259                (
25260                    empty(trim($postData['apiToken'])) &&
25261                    $postData['apiToken'] !== 0 &&
25262                    $postData['apiToken'] !== '0'
25263                )
25264            ) {
25265                $this->log(__METHOD__ . ' Missing parameters. post data --> ' . json_encode($postData), $logFileName);
25266                throw new BadRequestException("Missing parameter(s).");
25267            }
25268
25269            // set variables
25270            $apiToken = $postData['apiToken'];
25271            $formType = $postData['formType'];
25272            $successUrl = urldecode($postData['successUrl']);
25273            $paymentMethodType = $postData['paymentMethodType'];
25274            $nominalAmountArr = Configure::read('aftee.nominal_amount');
25275            $memKeyError = $postData['memKeyError'];
25276            $referrer = $postData['referrer'];
25277            $status = 0; // default pending
25278
25279            $userParams = array(
25280                'fields' => array(
25281                    'User.id',
25282                    'User.email',
25283                    'User.nickname',
25284                    'User.card_token',
25285                    'User.charge_flg',
25286                    'User.fail_flg',
25287                    'User.currency_code',
25288                    'User.payment_plan_id',
25289                    'User.price_id',
25290                    'User.double_check_flg',
25291                    'User.status',
25292                    'User.complimentary_code',
25293                    'User.card_company',
25294                    'User.phone_number',
25295                    'PaymentPlanPrice.amount'
25296            ),
25297                'apiToken' => $apiToken
25298            );
25299
25300            // throw exception if api token not exist
25301            if (!$userData = $this->User->getWPMobappUserData($userParams)) {
25302                $this->log(__METHOD__ . ' User api token does not exist. User params --> ' . json_encode($userParams), $logFileName);
25303                throw new InternalErrorException("User api token does not exist.");
25304            }
25305
25306            $userCurrencyCode = $userData['User']['currency_code'];
25307
25308            // set variables
25309            $paymentPlanPriceAmount = $userData['PaymentPlanPrice']['amount'];
25310            $userData = $userData['User'];
25311            $currencyCode = $userCurrencyCode;
25312            $paymentPlanId = $userData['payment_plan_id'];
25313            $priceId = $userData['price_id'];
25314            $userId = $userData['id'];
25315            $afteePaymentAmount = $nominalAmountArr[$currencyCode];
25316            $ncPaymentAmount = 0;
25317            $preToken = $userData['card_token'];
25318            $discounted_amount = isset($userData['discounted_amount']) ?? 0;
25319
25320
25321            // get payment method (debit or credit)
25322            $paymentMethod = 'aftee';
25323
25324            switch ($formType) {
25325                case Configure::read('payment_credit_authentication'):
25326                    $tokenReason = 'Payment Credit Registration';
25327                    if (!isset($priceId)) {
25328                        // get payment data
25329                        $paymentData = $this->PaymentPlanPrice->getPaymentData(array(
25330                            'currencyCode' => $currencyCode,
25331                            'paymentPlanId' => Configure::read('payment_plans.free_trial'),
25332                            'logFileName' => $logFileName
25333                        ));
25334
25335                        // throw error exception if does not exist
25336                        if (!$paymentData) {
25337                            throw new InternalErrorException("Payment plan does not exist.");
25338                        }
25339
25340                        $priceId = $paymentData['priceId'];
25341                    }
25342                    $paymentPlanId = Configure::read('payment_plans.free_trial');
25343                    break;
25344                case Configure::read('payment_credit_change'):
25345                    if (!isset($priceId) || !isset($paymentPlanId)) {
25346                        throw new InternalErrorException("Price id or payment plan id is/are empty.");
25347                    }
25348                    $tokenReason = 'Payment Credit Change';
25349                    break;
25350                case Configure::read('payment_credit_retry'):
25351                    // get payment data
25352                    if (!$paymentData = $this->getRetryPaymentData($userData, $logFileName)) {
25353                        throw new InternalErrorException("Payment plan does not exist.");
25354                    }
25355
25356                    $afteePaymentAmount = $paymentData['amount'];
25357                    $priceId = $paymentData['priceId'];
25358                    $paymentPlanId = $paymentData['paymentPlanId'];
25359                    
25360                    // NJ-47740
25361                    $coupon = $this->UsersCouponV1->getCouponUseRequest(array(
25362                        'userId' => $userId,
25363                        'kbn' => Configure::read('coupon_kbn.monthly_settlement')
25364                    ));
25365                    
25366                    if (
25367                        !empty($coupon['result']) && 
25368                        !empty($coupon['grp_id']) && 
25369                        !empty($coupon['amount']) && 
25370                        empty($coupon['has_payment']) // exclude if coupon has payment
25371                    ) {
25372                        $afteePaymentAmount -= $userData['discounted_amount'] = $coupon['amount'];
25373                        $userData['monthlyDiscount'] = $coupon['amount'];
25374                        $userData['monthly_grp_id'] = $coupon['grp_id'];
25375                    }
25376                    // NJ-47740 end
25377
25378                    // add reserve payment amount
25379                    $afteePaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment($userId);
25380
25381                    // add appreciation lesson amount
25382                    $afteePaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('appreciation_data.payment_element_type'));
25383
25384                    // add live lesson amount
25385                    $afteePaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.live'));
25386
25387                    $ncPaymentAmount = $afteePaymentAmount;
25388
25389                    // change payment method type to auth if amount to be paid in is equal to 0
25390                    if ($afteePaymentAmount == 0) {
25391                        $paymentMethodType = $paymentMethod . '_auth';
25392                        $afteePaymentAmount = $nominalAmountArr[$currencyCode];
25393                    }
25394
25395                    $tokenReason = 'Payment Credit Retry';
25396                    break;
25397                case Configure::read('payment_credit_force_charge'):
25398                    // get payment data
25399                    $paymentData = $this->PaymentPlanPrice->getPaymentData(array(
25400                        'currencyCode' => $currencyCode,
25401                        'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
25402                        'logFileName' => $logFileName
25403                    ));
25404
25405                    // throw error exception if does not exist
25406                    if (!$paymentData) {
25407                        throw new InternalErrorException("Payment plan does not exist.");
25408                    }
25409
25410                    $afteePaymentAmount = $paymentData['amount'];
25411                    $priceId = $paymentData['priceId'];
25412                    $paymentPlanId = $paymentData['paymentPlanId'];
25413
25414                    // add reserve payment amount
25415                    $afteePaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment($userId);
25416
25417                    // add live lesson payment amount
25418                    $afteePaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment( $userId, false, Configure::read('appreciation_data.payment_element_type') );
25419
25420                    // add live lesson payment amount
25421                    $afteePaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.live'));                    
25422
25423                    $ncPaymentAmount = $afteePaymentAmount;
25424
25425                    // change payment method type to auth if amount is  equal to 0
25426                    if ($afteePaymentAmount == 0) {
25427                        $paymentMethodType = $paymentMethod . '_auth';
25428                        $afteePaymentAmount = $nominalAmountArr[$currencyCode];
25429                    }
25430
25431                    $tokenReason = 'Payment Credit Charge';
25432                    break;
25433            }
25434            $validatePhone = "/^[0-9]{10}+$/";
25435            $phoneNumber = '';
25436            if (preg_match($validatePhone, $userData['phone_number']) === 1 && substr($userData['phone_number'], 0, 2) == '09' && strlen($userData['phone_number']) == 10) {
25437                $phoneNumber = $userData['phone_number'];
25438            }
25439            $orderNumber = myTools::generateOrderCode($userId);
25440            $merchantCode = myTools::getAfteeMerchantCode();
25441            $afteePaymentParams = array(
25442                'shopItemId' => "AFTEE" . $formType,
25443                'itemName' => str_replace(' ', '', $tokenReason),
25444                'itemPrice' => $afteePaymentAmount,
25445                'itemCount' => 1,
25446                'customerPhoneNumber' => $phoneNumber,
25447                'customerEmail' => $userData['email'],
25448                'shopTransactionNo' => $orderNumber,
25449                'userID' => $userId
25450            );
25451
25452            if (!class_exists('AfteePaymentService')) {
25453                App::uses('AfteePaymentService','Lib');
25454            }
25455            $afteeService = new AfteePaymentService();
25456            $auth = ($formType == Configure::read('payment_credit_authentication') || $formType == Configure::read('payment_credit_change')) ? true : false;
25457            $afteeChecksum = $afteeService->generateChecksum($afteePaymentParams, $auth);
25458            $afteeChecksum['settlementData']['checksum'] = $afteeChecksum['checksum'];
25459            $afteePublicKey = $afteeService->getShopPublicKey();
25460
25461            $paymentParams = array(
25462                'currencyCode' => $currencyCode,
25463                'formType' => $formType,
25464                'logFileName' => $logFileName,
25465                'remoteAddress' => $_SERVER["REMOTE_ADDR"],
25466                'cardToken' => isset($userData['card_token']) ? $userData['card_token'] : null,
25467                'newCard' => true,
25468                'merchantCode' => $merchantCode,
25469                'afteePaymentAmount' => $afteePaymentAmount,
25470                'paymentAmount' => $ncPaymentAmount,
25471                'priceId' => $priceId,
25472                'paymentPlanId' => $paymentPlanId,
25473                'paymentType' => Configure::read('payment_types.payment_plan'),
25474                'discounted_amount' => $discounted_amount
25475            );
25476
25477            if (isset($postData['userRegister']) && $postData['userRegister']) {
25478                $paymentParams['userRegister'] = true;
25479
25480                $receiveBonus = UsersPointTable::checkIfUserReceiveBonusUponRegister($userId);
25481                if (!$receiveBonus && empty($userData['User']['complimentary_code'])) {
25482                    UsersPointTable::giveBonusCoins(['userId' => $userId, 'triggerNo' => 1]);
25483                }
25484            }
25485
25486            if ($formType != Configure::read('payment_credit_change')) {
25487                $membershipTypes = UserTable::getEngMembershipTypeData();
25488                $statusAfter = $membershipTypes[1]; // premium plan paid
25489
25490                /* -- get before status -- */
25491                if ($this->memcache->get('com_plan_user_' . $userId) && $userData && $userData['payment_plan_id'] == Configure::read('payment_plans.complimentary_plan')) {
25492                    $statusBefore = $membershipTypes[15]; // complimentary code
25493                    $paymentParams['bonusCoinFlg'] = 1;
25494                    $paymentParams['updateFirstChargeDate'] = true;
25495                } elseif ($userData['charge_flg'] == 0) {
25496                    // failed settlement
25497                    if ($userData['fail_flg'] == 1) {
25498                        $statusBefore = $membershipTypes[5];
25499                    // trial again
25500                    } elseif ($userData['fail_flg'] == 0 && $userData['double_check_flg'] == 1) {
25501                        $statusBefore = $membershipTypes[13];
25502                    // unsubscribed
25503                    } elseif ($userData['fail_flg'] == 0 && $userData['double_check_flg'] == 2) {
25504                        $statusBefore = $membershipTypes[12];
25505                    // temporary
25506                    } elseif ($userData['status'] == 0) {
25507                        $statusBefore = $membershipTypes[6];
25508                        $statusAfter = $membershipTypes[2]; // premium plan free
25509                    } else {
25510                        $statusBefore = null;
25511                    }
25512                }
25513
25514                if (isset($statusBefore)) {
25515                    $user = new UserTable($userData);
25516                    $membershipTypeIndex = $user->getMembershipTypeIndex();
25517
25518                    if ($membershipTypeIndex == 13) {
25519                        $statusBefore = $membershipTypes[13];
25520                        $paymentParams['userRegister'] = true;
25521                        $statusAfter = $membershipTypes[2];
25522                    }
25523
25524                    // get platform use
25525                    $platform = myTools::mobappDetectPlatform();
25526                    $paymentParams['platform'] = $platform == Configure::read('platform.splp') ? Configure::read('platform.pclp') : $platform;
25527                    $paymentParams['statusBefore'] = $statusBefore;
25528                    $paymentParams['statusAfter'] = $statusAfter;
25529
25530                    $user = new UserTable($userData);
25531                    $membershipTypeIndex = $user->getMembershipTypeIndex();
25532
25533                    if ($membershipTypeIndex == 13) {
25534                        $paymentParams['userRegister'] = true;
25535                    }
25536                }
25537            }
25538            
25539            // NC-7029: coupon discount
25540            // exclude native option and callan option coupon discount (will use on later monthly settlement)
25541            $coupon = $this->UsersCouponV1->getCouponUseRequest(array(
25542                'userId' => $userId,
25543                'kbn' => Configure::read('coupon_kbn.monthly_settlement')
25544            ));
25545            
25546            if (
25547                !empty($coupon['result']) && 
25548                !empty($coupon['grp_id']) && 
25549                !empty($coupon['amount']) && 
25550                empty($coupon['has_payment']) // exclude if coupon has payment
25551            ) {
25552                $paymentParams['discounted_amount'] = $coupon['amount'];
25553                $paymentParams['monthlyDiscount'] = $coupon['amount'];
25554                $paymentParams['monthly_grp_id'] = $coupon['grp_id'];
25555            }
25556
25557            $ptParams = array(
25558                'user_id' => $userId,
25559                'payment_hash' => $orderNumber,
25560                'status' => $status,
25561                'payment_params' => json_encode($paymentParams),
25562                'course_id' => Configure::read("credit.course_id")
25563            );
25564
25565            // throw exception if failed to save payment transaction
25566            if (!$pt = $this->PaymentTransaction->setAfteePaymentTransaction($ptParams)) {
25567                $this->log(__METHOD__ .' Failed to save payment transaction. update data --> ' . json_encode($ptParams), $logFileName);
25568                throw new InternalErrorException("Failed to save payment transaction.");
25569            }
25570
25571            $this->set('logFileName', $logFileName);
25572            $this->set('apiToken', $apiToken);
25573            $this->set('checkSum', $afteeChecksum['checksum']);
25574            $this->set('orderNumber', $orderNumber);
25575            $this->set('userId', $userId);
25576            $this->set('salesSettled', $auth ? 'false' : 'true');
25577            $this->set('afteePaymentParams', $afteePaymentParams);
25578            $this->set('afteePublicKey', $afteePublicKey);
25579            $this->set('transactionOptions', $auth);
25580            $this->set('nc_terminal_type', isset($postData['ncTerminalType']) ? $postData['ncTerminalType'] : 0);
25581            $this->set('formType', $formType);
25582            $this->set('memKeyError', 'card_regist_error_'.$apiToken);
25583            $this->set('referrer', $postData['referrer']);
25584            $this->set('successUrl', $postData['successUrl']);
25585            $this->set('userRegister', true);
25586            $this->set('ptID', $pt['id']);
25587            $this->set('preToken', $preToken);
25588        } else {
25589            throw new MethodNotAllowedException("Method used is not POST.");
25590        }
25591
25592        $this->render('/Elements/mobapp/aftee_get_hosted_page');
25593    }
25594
25595    /**
25596     * Aftee payment webhook
25597     * Kickback from aftee after payment success
25598     */
25599    public function getAfteePaymentResult(){
25600        $this->autoRender = $this->autoLayout = false;
25601        $data = $this->request->data;
25602
25603        $this->log('fetched aftee result --> ' . json_encode($data), 'aftee_debug');
25604        $orderCode = isset($data['shop_transaction_no']) && !empty($data['shop_transaction_no']) ? $data['shop_transaction_no'] : NULL;
25605        $dataJson = json_encode($data);
25606
25607        // get payment transaction data 
25608        $paymentTransactionData = $this->PaymentTransaction->getAfteePaymentTransaction($orderCode);
25609
25610        // return if payment transaction does not exist
25611        if (!$paymentTransactionData) {
25612            $msg = 'Payment transaction does not exist.';
25613            $this->log(__METHOD__ . ' ' . $msg . ' kickback data -->' . $dataJson, 'aftee_debug');
25614            exit;
25615        }
25616        $updateData = array(
25617            'id' => $paymentTransactionData['id'],
25618            'fields' => array(
25619                'response_text' => array('aftee_directPayment_response' => $dataJson))
25620        );
25621
25622        // update payment transaction with kickback data
25623        if (!$this->PaymentTransaction->updateAfteePaymentTransaction($updateData)) {
25624            $this->log(__METHOD__ .' Failed to update payment transaction. update data --> ' . json_encode($updateData), 'aftee_debug');
25625            exit;
25626        }
25627
25628        echo "[OK]"; exit;
25629    }
25630
25631    /**
25632     * Aftee authentication webhook
25633     * Kickback from aftee if phone number is valid
25634     */
25635    public function afteeAuthentication(){
25636        $this->autoRender = $this->autoLayout = false;
25637        $this->log('aftee authentication --> ' . json_encode($this->request->data), 'aftee_debug');
25638        exit;
25639    }
25640
25641    /**
25642     * NC-18006: aftee process payment transaction.
25643     * @param array $params
25644     * @return string 'ok' or exception
25645     */
25646    private function processAfteePayment($params) {
25647        $logFileName = isset($params['logFileName']) ? $params['logFileName'] : 'debug';
25648        $orderCode = isset($params['data']['OrderCode']) ? $params['data']['OrderCode'] : '';
25649        $paymentStatusName = isset($params['data']['PaymentStatus']) ? $params['data']['PaymentStatus'] : '';
25650        $userId = isset($params['ptData']['user_id']) ? $params['ptData']['user_id'] : null;
25651
25652        if (
25653            !isset($params['data']) || !isset($params['ptData']) || !isset($params['dataSource']) ||
25654            !isset($params['amount']) || !isset($params['userData'])
25655        ) {
25656            $msg = ' Missing parameters.';
25657            $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
25658            $this->log(__METHOD__ . ' ' . $msg . ' Parameters --> ' . json_encode($params), $logFileName);
25659        }
25660
25661        $membershipStatusIndex = UserTable::getStudentMembershipStatus($userId);
25662
25663        // set variables
25664        $data = $params['data'];
25665        $dataJson = json_encode($data);
25666        $dateNow = date("Y-m-d H:i:s");
25667        $paymentTransactionData = $params['ptData'];
25668        $cardCompany = Configure::read('card_company.aftee');
25669        $amount = $params['amount'];
25670        $paymentStatus = 1;
25671        $typeId = 1;
25672        $platform = Configure::read('platform.pclp');
25673        $receivablePayment = isset($params['receivablePayment']) ? $params['receivablePayment'] : 0;
25674        $appreciationReceivable = isset($params['appreciationReceivable']) ? $params['appreciationReceivable'] : 0;
25675        $liveLessonReceivable = isset($params['liveLessonReceivable']) ? $params['liveLessonReceivable'] : 0;
25676        $ptPaymentParams = json_decode($paymentTransactionData['payment_params'], true);
25677        $currencyCode = isset($ptPaymentParams['currencyCode']) ? $ptPaymentParams['currencyCode'] : null;
25678        $ptResponseText = array('aftee_kickback' => $data);
25679        $dataSource = $params['dataSource'];
25680        $ptPassword = $paymentTransactionData['password'];
25681        $formType = $ptPaymentParams['formType'];
25682        $cronDateRun = isset($params['cronDateRun']) ? $params['cronDateRun'] : date('Y-m-d H:i:s');
25683        $userData = $params['userData'];
25684        $transactionIdentifier = $params['transactionIdentifier'];
25685        $paymentPlanId = isset($ptPaymentParams['paymentPlanId']) ? $ptPaymentParams['paymentPlanId'] : null;
25686        $paymentType = isset($ptPaymentParams['paymentType']) ? $ptPaymentParams['paymentType'] : null;
25687        $discounted_amount = isset($ptPaymentParams['discounted_amount']) ? $ptPaymentParams['discounted_amount'] : 0;
25688        $priceId = isset($ptPaymentParams['priceId']) ? $ptPaymentParams['priceId'] : null;
25689        $familyId = isset($ptPaymentParams['familyId']) ? $ptPaymentParams['familyId'] : null;
25690        $parentId = isset($userData['User']['parent_id']) ? $userData['User']['parent_id'] : $ptPaymentParams['parentId'];
25691
25692        $userId = $familyId ? $familyId : $userId;
25693
25694
25695        $currency_before = $currencyCode;
25696        $plan_before = $paymentPlanId;
25697        $membershipStatusIndex = isset($ptPaymentParams['membershipStatusIndex']) && $ptPaymentParams['membershipStatusIndex'] ? $ptPaymentParams['membershipStatusIndex'] : $membershipStatusIndex;
25698        $uModel = $this->User;
25699
25700        if (in_array($formType, array(Configure::read('payment_credit_retry'), Configure::read('payment_credit_authentication')))) {
25701            $typeId = 2;
25702        } 
25703
25704        if (isset($amount) && $amount < 0) {
25705            $typeId = 0;
25706        }
25707
25708        $userData = $userData['User'];
25709        $pModel = $this->Payment;
25710
25711        // check if family plan
25712        if (
25713            $familyId && 
25714            $parentId && 
25715            (
25716                in_array($formType, array(Configure::read('payment_credit_coin_purchase'), Configure::read('payment_credit_textbook_purchase'))) 
25717                ||
25718                (
25719                    isset($ptPaymentParams['nativeOptionJoin']) && 
25720                    $ptPaymentParams['nativeOptionJoin'] && 
25721                    $ptPaymentParams['formType'] == Configure::read('payment_native_option_join')
25722                )
25723            )
25724        ) {
25725            // change reference id to parent id
25726            $referenceId = $parentId;
25727        } else {
25728            $referenceId = $userId;
25729        }
25730
25731        // set variables
25732        $paymentData = array(
25733            'user_id' => $userId,
25734            'type_id' => $typeId,
25735            'reference_id' => $referenceId,
25736            'payment_transaction_password' => $ptPassword,
25737            'status' => $paymentStatus,
25738            'form_type' => $formType,
25739            'ordd' => $orderCode,
25740            'amount' => $amount,
25741            'param1' => $dataJson,
25742            'card_company' => $cardCompany,
25743            'transaction_code' => $orderCode,
25744            'currency_code' => $currencyCode,
25745            'payment_id' => $paymentPlanId,
25746            'price_id' => $priceId,
25747            'payment_type' => $paymentType,
25748        );
25749
25750        // NC-7029: save discount amount
25751        if (isset($ptPaymentParams['discounted_amount']) && $ptPaymentParams['discounted_amount'] > 0) {
25752            $paymentData['discounted_amount'] = $ptPaymentParams['discounted_amount'];
25753        }
25754
25755        //- check payment receivable with zero amount
25756        if (
25757            $formType == Configure::read('payment_credit_receivable') &&
25758            $amount <= 0
25759        ) {
25760            //- skip saving
25761        } else {
25762            // create new payment
25763            $pModel->clear();
25764            $pModel->create();
25765            $pModel->validate = array();
25766            $pModel->set($paymentData);
25767
25768            // return if not save
25769            if (!$paymentSave = $pModel->save()) {
25770                $msg = 'Saving payment failed.';
25771                $this->log(__METHOD__ . ' ' . $msg . ' Payment data --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, $logFileName);
25772                $dataSource->rollback();
25773                $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
25774                throw new InternalErrorException($msg);
25775            }
25776            //update/add user`s settlement amount
25777            $this->User->updateUserPayments($paymentData);
25778            $paymentId = $paymentSave['Payment']['id'];
25779
25780            // set payment_id
25781            $paymentSaveID = $this->Payment->id;
25782        }
25783
25784        // if payment was saved, and form type belongs to textbook purchase,
25785        // update textbook_sales table, insert payment_id
25786        if ($formType == Configure::read('payment_credit_textbook_purchase')) {
25787            // set textbook sales info
25788            $textbookSales = $this->TextbookSale->find('first', array(
25789                'conditions' => array(
25790                    'TextbookSale.sales_code' => $ptPassword
25791                ),
25792                'recursive' => -1
25793            ));
25794            
25795            // if has textbook sales, update payment_id
25796            if ($textbookSales) {
25797                $this->TextbookSale->clear();
25798                if (!$this->TextbookSale->read(null, $textbookSales['TextbookSale']['id'])) {
25799                    $msg = 'Textbook sales id does not exist.';
25800                    $this->log(__METHOD__ . ' ' . $msg . json_encode($textbookSales), $logFileName);
25801                    $dataSource->rollback();
25802                    $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
25803                }
25804                $this->TextbookSale->set('payment_id', $paymentId);
25805                $this->TextbookSale->set('payment_status', 1);
25806                if (!$this->TextbookSale->save()) {
25807                    $msg = 'Failed to update textbook sales payment status to 1.';
25808                    $this->log(__METHOD__ . ' ' . $msg . json_encode($textbookSales), $logFileName);
25809                    $dataSource->rollback();
25810                    $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
25811                    throw new InternalErrorException($msg);
25812                }
25813            }
25814        }
25815
25816        // check if form type is not equals to textbook purchase or receivable
25817        if (
25818            $formType != Configure::read('payment_credit_coin_purchase') &&
25819            $formType != Configure::read('payment_credit_textbook_purchase') &&
25820            $formType != Configure::read('payment_credit_receivable') &&
25821            $formType != Configure::read('payment_credit_appreciation_receivable') &&
25822            $formType != Configure::read('payment_native_option_monthly_payment') &&
25823            $formType != Configure::read('payment_native_option_join')
25824        ) {
25825            // set user array to be save
25826            $saveUserArr = array(
25827                'modified' => $dateNow,
25828                'fail_flg' => 0,
25829                'charge_flg' => 1,
25830                'counseling_attended_flg' => 0,
25831                'card_company' => $cardCompany,
25832                'hash16' => $userId,
25833                'last_charge_date' => $dateNow,
25834                'aftee_transaction_identifier' => $transactionIdentifier,
25835                'payment_plan_id' => $paymentPlanId,
25836                'price_id' => $priceId
25837            );
25838
25839            // NJ-1562 - appreciation on
25840            if( $paymentPlanId && in_array( $paymentPlanId, Configure::read('appreciation.payment_plan_id') ) ) {
25841                $saveUserArr['allow_appreciation_flg'] = 1; // on
25842
25843                //NJ-7548 : 
25844                if (
25845                    !in_array($paymentPlanId,Configure::read('appreciation.can_coin_purchase_check')) &&
25846                    (
25847                        $formType == Configure::read('payment_credit_authentication') ||
25848                        $formType == Configure::read('payment_credit_change') || 
25849                        $formType == Configure::read('payment_credit_force_charge') || 
25850                        $formType == Configure::read('payment_credit_retry')
25851                    )
25852                ) {
25853                    //fetch the age
25854                    $userAge = UserTable::getStudentAge($userData['birthday']);
25855                    $userAge = $userAge ? (int) $userAge : null;
25856                    $showAppreciationFlg = 0;
25857
25858                    //change the show appreciation flg if no birthday set or 18 and above            
25859                    if (!$userAge || $userAge >= 18) {
25860                        $saveUserArr['show_appreciation_flg'] = 1; // on
25861                    }
25862                }
25863
25864            }
25865
25866            // check payment if credit authentication
25867            if (in_array($formType, array(Configure::read('payment_credit_authentication'), Configure::read('payment_credit_family_free'))) 
25868                || isset($ptPaymentParams['updateFirstChargeDate'])
25869            ) {
25870                $saveUserArr['first_charge_date'] = $dateNow;
25871                // $saveUserArr['platform'] = $platform;
25872            }
25873
25874            // if bonus coin flg is set
25875            if (isset($ptPaymentParams['bonusCoinFlg'])) {
25876                $saveUserArr['bonus_coin_flg'] = $ptPaymentParams['bonusCoinFlg'];
25877            }
25878
25879            // get time today plus 1 hour
25880            $nextChargeTime = (time() + 3600) - strtotime('TODAY');
25881
25882            // check if subscription payment
25883            if (
25884                $formType == Configure::read('payment_credit_force_charge') ||
25885                $formType == Configure::read('payment_credit_retry') ||
25886                $formType == Configure::read('payment_credit_monthly_payment') ||
25887                $formType == Configure::read('payment_credit_family_monthly_payment') ||
25888                $formType == Configure::read('payment_credit_family_free')
25889            ) {
25890
25891                if ($formType == Configure::read('payment_credit_monthly_payment')) {
25892                    $nextChargeTime = strtotime($userData['next_charge_date']) - strtotime('TODAY');
25893                }
25894
25895                // set minutes and seconds to 00:00 always
25896                $nextChargeDate = date('Y-m-d H:00:00', strtotime('+' . $nextChargeTime . ' second ' . $this->User->getNextChargeDate()));
25897                $saveUserArr['next_charge_date'] = $nextChargeDate;
25898                $saveUserArr['double_check_flg'] = 1;
25899                $saveUserArr['expired_card_flg'] = 0;
25900
25901                $this->loadModel("ContinuationCampaign");
25902
25903                // give points to user join the campaign who retry payment
25904                if ($formType == Configure::read('payment_credit_retry')) {
25905                    $this->ContinuationCampaign->givePointsRetrySuccess(array(
25906                        'user_ids' => array($userId)
25907                    ));
25908                }
25909
25910                // give points if user join campaign and success payment
25911                if ($formType == Configure::read('payment_credit_monthly_payment')) {
25912                    $this->ContinuationCampaign->givePoints(array(
25913                        'user_id' => $userId
25914                    ));
25915                }
25916
25917                if ($formType == Configure::read('payment_credit_family_free')) {                    
25918                    $nextChargeDate = date('Y-m-d H:00:00', strtotime('+' . $nextChargeTime . ' second ' . $this->User->getFirstNextChargeDate()));
25919                    $saveUserArr['next_charge_date'] = $nextChargeDate;
25920                }
25921
25922                if ($formType == Configure::read('payment_credit_family_monthly_payment')) {
25923                    $nextChargeDate = date('Y-m-d H:00:00', strtotime('+' . (time() - strtotime('TODAY')) . ' second ' . $this->User->getNextChargeDate()));
25924                    $saveUserArr['next_charge_date'] = $nextChargeDate;
25925                }
25926
25927
25928                # give coins if temporary/new user is changed/added to family plan
25929                if ($formType == Configure::read('payment_credit_family_free') && $userData['status'] == 0) {
25930                    // NJ-4746: defult bonus point
25931                    $defaultBC = ClassRegistry::init("DefaultCoinRegistration")->defaultCoins();
25932                    $bonusPoints = (($defaultBC > 0) ? $defaultBC : Configure::read("credit.bonus_coin_authentication"));
25933
25934                    // campaign master trigger 1
25935                    $campaignMaster = ClassRegistry::init('CampaignMaster')->bonusTrigger(['userId' => $userData['id'], 'triggerNo' => 1]);
25936                    if (!$campaignMaster['bonusCoins'] && !$campaignMaster['bonusCoupons']) {
25937                        # add to the user's existing coin
25938                        $pointParams = array(
25939                            'userId' => $userData['id'],
25940                            'point' => $bonusPoints,
25941                            'kbn' => Configure::read("point_history.bonus"),
25942                            'kbnType' => 1, // add coin
25943                            'coinType' => 2, // service coin
25944                            'coinFailMessage' => Configure::read('coin.failed.campaign')
25945                        );
25946                        if (!$this->UsersPoint->performPointTransaction($pointParams)) {
25947                            $msg = 'Failed add point to user.';
25948                            $this->log(__METHOD__ . ' Failed add point to user. ' . json_encode($pointParams) . ' -- ' . json_encode($data), $logFileName);
25949                            $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
25950                            $dataSource->rollback();
25951                            $dataSource->commit();
25952                            return ;
25953                        }
25954                    }
25955                }
25956
25957            } elseif ($formType == Configure::read('payment_credit_authentication')) {
25958                // set minutes and seconds to 00:00 always
25959                $nextChargeDate = date('Y-m-d H:00:00', strtotime('+' . $nextChargeTime . ' second ' . $this->User->getFirstNextChargeDate()));
25960                $saveUserArr['next_charge_date'] = $nextChargeDate;
25961            }
25962
25963            // if credit card change from android or apple to worldpay
25964            if (
25965                in_array($formType, array(Configure::read('payment_credit_change'), Configure::read('payment_credit_authentication'))) &&
25966                in_array($cardCompany, array(Configure::read('card_company.apple'), Configure::read('card_company.google')))
25967            ) {
25968
25969                $pointParams = array(
25970                    'userId' => $userId,
25971                    'point' => 500,
25972                    'kbn' => 6,
25973                    'kbnType' => 1, // add coin
25974                    'coinType' => 2, // service coin
25975                    'coinFailMessage' => Configure::read('coin.failed.campaign')
25976                );
25977
25978                if (!$this->UsersPoint->performPointTransaction($pointParams)) {
25979                    $msg = 'Adding user coin history failed.';
25980                    $this->log(__METHOD__ . ' ' . $msg . ' Point params --> ' . json_encode($pointParams) . ' | kickback data --> ' . $dataJson, $logFileName);
25981                    $dataSource->rollback();
25982                    $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
25983                    throw new InternalErrorException($msg);
25984                }
25985            }
25986
25987            $famRegist = false;
25988            // NC-4673: update family parent_id, memo and monthly_payment
25989            
25990            if (
25991                in_array($formType, Configure::read('family_plan_form_types'))
25992            ) {
25993                // if parent_id is empty
25994                if (empty($userData['parent_id'])) {
25995                    $saveUserArr['parent_id'] = $parentId;
25996                    $saveUserArr['memo'] = date('Y/m/d H:i:s')." Family plan[User]: family registration \n".$userData['memo'];
25997                    $famRegist = true;
25998
25999                    if (empty($userData['currency_code'])) {
26000                        $saveUserArr['currency_code'] = $currencyCode;
26001                    }
26002                }
26003            }
26004
26005            // get and set card token, card brand and card number
26006            // if not new registration, delete wp token
26007            if (
26008                $formType == Configure::read('payment_credit_change') ||
26009                ($formType == Configure::read('payment_credit_authentication') && isset($ptPaymentParams['newCard']) && $ptPaymentParams['newCard']) ||
26010                ($formType == Configure::read('payment_credit_retry') && isset($ptPaymentParams['newCard']) && $ptPaymentParams['newCard']) ||
26011                ($formType == Configure::read('payment_credit_force_charge') && isset($ptPaymentParams['newCard']) && $ptPaymentParams['newCard']) ||
26012                $formType == Configure::read('payment_credit_family_free') ||
26013                $formType == Configure::read('payment_credit_family_monthly_payment')
26014            ) {
26015                // if family plan payment use parent id
26016                if($formType == Configure::read('payment_credit_family_free') || $formType == Configure::read('payment_credit_family_monthly_payment')){
26017                    $authenticatedShopperId = $parentId;
26018                }else{
26019                    $authenticatedShopperId = $userId;
26020                }
26021            
26022                // set aftee authentication token
26023                $saveUserArr['card_token'] = $data['authentication_token'];
26024                $saveUserArr['card_brand'] = "AFTEE";
26025                $saveUserArr['card_number'] = substr($data['customer']['phone_number'], -4);
26026                $saveUserArr['aftee_transaction_identifier'] = $transactionIdentifier;
26027                $saveUserArr['card_company'] = Configure::read('card_company.aftee');
26028
26029            }
26030            // update user data
26031            $uModel->clear();
26032            $uModel->recursive = -1;
26033            $read = $uModel->read(array_keys($saveUserArr), $userId);
26034            $uModel->validate = array();
26035            $uModel->set($saveUserArr);
26036            if (!$uModel->save()) {
26037                $msg = 'Updating user failed.';
26038                $this->log(__METHOD__ . ' ' . $msg . ' User data --> ' . json_encode($saveUserArr) . ' | kickback data --> ' . $dataJson, $logFileName);
26039                $dataSource->rollback();
26040                $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
26041                throw new InternalErrorException($msg);
26042            }
26043
26044            // check if membership status was change
26045            if (isset($ptPaymentParams['statusBefore']) && isset($ptPaymentParams['statusAfter']) && isset($ptPaymentParams['platform'])) {
26046                $currentUser = $this->User->find('first', array(
26047                    'fields' => array('User.parent_id', 'User.currency_code', 'User.payment_plan_id'),
26048                    'conditions' => array('User.id' => $userId),
26049                    'recursive' => -1
26050                ));
26051                $parentId = $currentUser['User']['parent_id'];
26052                $is_cron = 0;
26053                if (php_sapi_name() == 'cli' || $ptPaymentParams['logFileName'] == 'retry_monthly_payment'){
26054                    $is_cron = 1;
26055                } 
26056                   $currency_after = $currentUser['User']['currency_code'];
26057                   $plan_after = $currentUser['User']['payment_plan_id'];
26058                $usclData = array(
26059                    'user_id' => $userId,
26060                    'platform' => $ptPaymentParams['platform'] ?? '',
26061                    'card_company_before' => $read['User']['card_company'],
26062                    'status_before' => $ptPaymentParams['statusBefore'],
26063                    'status_after' => $ptPaymentParams['statusAfter'],
26064                    'controller_name' => $this->request->params['controller'],
26065                    'action_name' => $this->request->params['action'],
26066                    'parent_id' => $parentId,
26067                    'is_cron' => $is_cron,
26068                    'currency_before' => $currency_before,
26069                    'currency_after' => $currency_after,
26070                    'payment_plan_id_before' => $plan_before,
26071                    'payment_plan_id_after' => $plan_after
26072                );
26073
26074                // save user change membership status
26075                if (!$this->UserStatusChangeLog->saveLog($usclData)) {
26076                    $msg = 'Saving user status change log failed.';
26077                    $dataSource->rollback();
26078                    $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
26079                    throw new InternalErrorException($msg);
26080                }
26081            }
26082
26083            // NC-7459 check previus user status, add coinbox challenge
26084            if (
26085                isset($userData['payment_plan_id'])
26086                && $userData['payment_plan_id'] == Configure::read('payment_plans.complimentary_plan')
26087                && isset($userData['complimentary_code'])
26088            ) {
26089
26090                // get complimentary coin award
26091                $coinAward = $this->ComplimentaryCode->find('first', array(
26092                    'fields' => array('coin_award'),
26093                    'conditions' => array(
26094                        'ComplimentaryCode.code' => $userData['complimentary_code'],
26095                        'ComplimentaryCode.template_type !=' => 0 // Free trial
26096                    )
26097                ));
26098
26099                if (
26100                    isset($coinAward['ComplimentaryCode']['coin_award'])
26101                    && $coinAward['ComplimentaryCode']['coin_award']
26102                ) { // @TODO use common @note did not use CoinBox->addCoinReward because it will not succeed for unknown reason.
26103                    $coinboxSet = array(
26104                        'status' => 1,
26105                        'user_id' => $userId,
26106                        'teacher_id' => null,
26107                        'coin_event_id' => Configure::read('coin_box_event.complimentary'),
26108                        'coin' => $coinAward['ComplimentaryCode']['coin_award'],
26109                        'lesson_id' => NULL,
26110                        'expiration_date' => date('Y-m-d 23:59:59', strtotime('+59 days'))
26111                    );
26112                    $this->CoinBox->create();
26113                    $this->CoinBox->set($coinboxSet);
26114                    if (!$this->CoinBox->save()) {
26115                        $msg = 'Saving user coin box failed.';
26116                        $dataSource->rollback();
26117                        $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
26118                        throw new InternalErrorException($msg);
26119                    }
26120                }
26121            }
26122
26123            // if parent user update children's card company
26124            if ($formType == Configure::read('payment_credit_change')) {
26125                $childList = $this->User->getChildId($userId);
26126                // check if user is parent
26127                if (!empty($childList)) {
26128                    foreach ($childList as $childId) {
26129                        $this->User->clear();
26130                        $updateCCArr = array('card_company' => $cardCompany);
26131                        if (!$this->User->read(array_keys($updateCCArr), $childId)) {
26132                            $this->log(__METHOD__ . ' child id does not exist.  --> ' . json_encode($updateCCArr) . ' | parent id --> ' . $userId . ' | aftee data --> ' . json_encode($ptPaymentParams), $logFileName);
26133                            $dataSource->rollback();
26134                            $dataSource->commit();
26135                            return ;
26136                        }
26137
26138                        $this->User->set($updateCCArr);
26139                        if (!$this->User->save()) {
26140                            $this->log(__METHOD__ . ' failed to update child card company.   --> ' . json_encode($updateCCArr) . ' | parent id --> ' . $userId . ' | aftee data --> ' . json_encode($ptPaymentParams), $logFileName);
26141                            $dataSource->rollback();
26142                            $dataSource->commit();
26143                            return ;
26144                        }
26145                    }
26146                }
26147            }
26148
26149            $memKey = 'family_reactivation_' . $parentId . '_' . $familyId;
26150            $familyReactivation = $this->memcache->get($memKey);
26151
26152            // NC-3754 : add memo for reactivation parent user.
26153            if ($formType == Configure::read('payment_credit_family_monthly_payment') && !empty($userData['parent_id']) && $familyReactivation) {
26154                $famRegist = false;
26155                // delete memcache
26156                $this->memcache->delete($memKey);
26157                $this->User->clear();
26158                if (!$userRead = $this->User->read(array('memo'), $parentId)) {
26159                    $msg = 'User id does not exist';
26160                    $this->log(__METHOD__ . ' User id does not exist. ' . json_encode($ptPaymentParams), $logFileName);
26161                    $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
26162                    $dataSource->rollback();
26163                    $dataSource->commit();
26164                    return ;
26165                }
26166
26167                $this->User->set(array('memo' => date('Y/m/d H:i:s')." Family plan[User]: family id: " . $userData['id'] . " reactivation \n" . $userRead['User']['memo']));
26168                $this->User->validate = false;
26169                if (!$this->User->save()) {
26170                    $msg = 'User id does not exist';
26171                    $this->log(__METHOD__ . ' Failed update user data. ' . json_encode($userRead) . ' -- ' . json_encode($ptPaymentParams), $logFileName);
26172                    $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
26173                    $dataSource->rollback();
26174                    $dataSource->commit();
26175                    return ;
26176                }
26177            }
26178            
26179            // Proccess Family Plan
26180            if($famRegist && !$familyReactivation) {
26181                // @param:  parent id. for memcache key.
26182                $famPlanRes = $this->FamilyPlanList->processFamPlan($parentId, $familyId, $orderCode);
26183                if ($famPlanRes != "[OK]") {
26184                    $msg = 'Failed processing family plan.';
26185                    $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
26186                    $dataSource->rollback();
26187                    $dataSource->commit();
26188                    return;
26189                }
26190            }
26191            
26192            // check if user's status is temporary
26193            if (
26194                $userData['status'] == 0 && 
26195                (
26196                    $formType == Configure::read('payment_credit_authentication') || 
26197                    $formType == Configure::read('payment_credit_family_monthly_payment') || 
26198                    $formType == Configure::read('payment_credit_family_free')
26199                )
26200            ) {
26201                // update user's status after step 4
26202                $uModel->clear();
26203                $uModel->read(array('status'), $userId);
26204                $uModel->validate = array();
26205                $uModel->set('status', 1);
26206                if (!$uModel->save()) {
26207                    $msg = 'Failed to update user status into 1.';
26208                    $this->log(__METHOD__ . ' ' . $msg . ' User id --> ' . json_encode($userId) . ' | kickback data --> ' . $dataJson, $logFileName);
26209                    $dataSource->rollback();
26210                    $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
26211                    throw new InternalErrorException($msg);
26212                }
26213            }
26214            
26215            // NC-7779 : check if user has chivox monthly test taken for the current month, and monthly_speaking_attended_flg ON,
26216            // turn Off the flag if users has not yet taken the exam for the current month.
26217            if (
26218                isset($userData['monthly_speaking_attended_flg']) && isset($userData['monthly_speaking_business_attended_flg'])
26219                && ($userData['monthly_speaking_attended_flg'] == 1 || $userData['monthly_speaking_business_attended_flg'] == 1)
26220            ) {
26221                // check chivox monthly
26222                $paymentPlanIdsForChivoxMonthly = Configure::read('chivox.monthly.user_payment_plan_cantake_exam');
26223                if (in_array($paymentPlanId, $paymentPlanIdsForChivoxMonthly)) {
26224
26225                    // load model
26226                    $this->loadModel("UsersChivoxMonthlyTest");
26227                    $userTestMonthFlagParams['user_id'] = $userId;
26228                    $userTestMonthFlag = $this->UsersChivoxMonthlyTest->checkUserCurrentMonthExam($userTestMonthFlagParams);
26229
26230                    $monthly_speaking_attended_flg = Configure::read('chivox.test_data_test_type.daily'); // test_type daily speaking 0
26231                    $monthly_speaking_business_attended_flg = Configure::read('chivox.test_data_test_type.business'); // test_type business 1
26232                    $fieldsToUpdate = array();
26233
26234                    // if user hat not yet taken the exam for current month
26235                    if (!in_array($monthly_speaking_attended_flg, $userTestMonthFlag)) {
26236                        $fieldsToUpdate['monthly_speaking_attended_flg'] = 0;
26237                    }
26238                    if (!in_array($monthly_speaking_business_attended_flg, $userTestMonthFlag)) {
26239                        $fieldsToUpdate['monthly_speaking_business_attended_flg'] = 0;
26240                    }
26241
26242                    if ($fieldsToUpdate) {
26243                        $uModel->clear();
26244                        $uModel->recursive = -1;
26245                        $uModel->read(array_keys($fieldsToUpdate), $userId);
26246                        $uModel->validate = array();
26247                        $uModel->set($fieldsToUpdate);
26248                        if (!$uModel->save()) {
26249                            $msg = 'Failed to update user monthly_speaking_attended_flg into 0.';
26250                            $this->log(__METHOD__ . ' ' . $msg . ' User id --> ' . json_encode($userId) . ' | kickback data --> ' . $dataJson, $logFileName);
26251                            $dataSource->rollback();
26252                            $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
26253                            throw new InternalErrorException($msg);
26254                        }
26255                    }
26256                }
26257            }
26258        }
26259
26260        // if purchase coin
26261        if ($formType == Configure::read('payment_credit_coin_purchase') && isset($ptPaymentParams['coinPurchasePoints'])) {
26262            // change user id to child id
26263            if($familyId){
26264                $pointParamsUserId = $familyId;
26265            }else{
26266                $pointParamsUserId = $userId;
26267            }
26268
26269            $pointParams = array(
26270                'userId' => $pointParamsUserId,
26271                'point' => $ptPaymentParams['coinPurchasePoints'],
26272                'kbn' => 7,
26273                'kbnType' => 1, // add coins
26274                'coinType' => 1, // purchase coins
26275                'device' => isset($ptPaymentParams['device']) ? $ptPaymentParams['device'] : null
26276            );
26277
26278            if (!$this->UsersPoint->performPointTransaction($pointParams)) {
26279                $msg = 'Adding user coin history failed.';
26280                $this->log(__METHOD__ . ' ' . $msg . json_encode($pointParams) . ' -- ' . $dataJson, $logFileName);
26281                $dataSource->rollback();
26282                $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
26283                throw new InternalErrorException($msg);
26284            }
26285        }
26286
26287        // [Aftee] check if receivable payment sent was either
26288        // receivable payment, monthly payment, force settlement, or retry payment
26289        // if yes, set receivable payments to "received"
26290        if (
26291            in_array($formType, array(
26292                Configure::read('payment_credit_appreciation_receivable'),
26293                Configure::read('payment_credit_receivable'),
26294                Configure::read('payment_credit_monthly_payment'),
26295                Configure::read('payment_credit_force_charge'),
26296                Configure::read('payment_credit_retry'),
26297                Configure::read('payment_credit_family_monthly_payment')
26298            ))
26299        ) {
26300            // create new payment receivable
26301            if ($formType != Configure::read('payment_credit_receivable') && $receivablePayment) {
26302                // set payment id
26303                $data["payment_id"] = $paymentId;
26304
26305                // set variables
26306                $paymentData = array(
26307                    'user_id' => $userId,
26308                    'type_id' => $typeId,
26309                    'reference_id' => $userId,
26310                    'status' => $paymentStatus,
26311                    'form_type' => Configure::read('payment_credit_receivable'),
26312                    'ordd' => $orderCode,
26313                    'amount' => $receivablePayment,
26314                    'param1' => $dataJson,
26315                    'card_company' => $cardCompany,
26316                    'transaction_code' => $orderCode,
26317                    'currency_code' => $currencyCode,
26318                    'payment_id' => $paymentPlanId,
26319                    'price_id' => $priceId,
26320                    'payment_type' => $paymentType,
26321                    'discounted_amount' => 0
26322                );
26323
26324                // create new payment
26325                $pModel->clear();
26326                $pModel->create();
26327                $pModel->validate = array();
26328                $pModel->set($paymentData);
26329
26330                if (!$pModel->save()) {
26331                    $msg = 'Saving payment receivable failed.';
26332                    $this->log(__METHOD__ . ' ' . $msg . ' Params --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, $logFileName);
26333                    $dataSource->rollback();
26334                    $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
26335                    throw new InternalErrorException($msg);
26336                }
26337                //update/add user`s settlement amount
26338                $this->User->updateUserPayments($paymentData);
26339                // set payment_id
26340                $paymentId = $pModel->id;
26341
26342            }
26343
26344            // set payment receivable statuses to 2 - received
26345            $this->PaymentReceivable->updateReceivableReservationPayment(
26346                $userId, 
26347                array(
26348                    'status' => 2,
26349                    'payment_id' => $paymentId,
26350                    'payment_collection_date' => $dateNow,
26351                    'card_company' => $cardCompany,
26352                    'payment_plan_id' => $paymentPlanId,
26353                    'membership_type_index' => $membershipStatusIndex
26354                ),
26355                array(
26356                    'PaymentReceivable.user_id' => $userId,
26357                    'PaymentReceivable.status' => 0,
26358                    'PaymentReceivable.payment_element_type' => 1,
26359                    'PaymentReceivable.created <=' => $cronDateRun
26360                )
26361            );
26362
26363            // create new appreciation lesson payment receivable
26364            if ($formType != Configure::read('payment_credit_appreciation_receivable') && $appreciationReceivable > 0) {
26365                // set payment id
26366                $data["payment_id"] = $paymentId;
26367                //reset payment data
26368                $paymentData = array();
26369
26370                // set variables
26371                $paymentData = array(
26372                    'user_id' => $userId,
26373                    'type_id' => $typeId,
26374                    'reference_id' => $userId,
26375                    'status' => $paymentStatus,
26376                    'form_type' => Configure::read('appreciation_data.payment_form_type'),
26377                    'ordd' => $orderCode,
26378                    'amount' => $appreciationReceivable,
26379                    'param1' => $dataJson,
26380                    'card_company' => $cardCompany,
26381                    'transaction_code' => $orderCode,
26382                    'currency_code' => $currencyCode,
26383                    'payment_id' => $paymentPlanId,
26384                    'price_id' => $priceId,
26385                    'payment_type' => $paymentType,
26386                    'discounted_amount' => 0
26387                );
26388
26389                // create new payment
26390                $pModel->clear();
26391                $pModel->create();
26392                $pModel->validate = array();
26393                $pModel->set($paymentData);
26394
26395                if (!$pModel->save()) {
26396                    $msg = 'Saving appreciation payment receivable failed.';
26397                    $this->log(__METHOD__ . ' ' . $msg . ' Params --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, $logFileName);
26398                    $dataSource->rollback();
26399                    $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
26400                    throw new InternalErrorException($msg);
26401                }
26402                //update/add user`s settlement amount
26403                $this->User->updateUserPayments($paymentData);
26404                // set payment_id
26405                $paymentId = $pModel->id;
26406    
26407            }
26408
26409            // set payment receivable statuses to 2 - received
26410            $this->PaymentReceivable->updateReceivableReservationPayment(
26411                $userId, 
26412                array(
26413                    'status' => 2,
26414                    'payment_id' => $paymentId,
26415                    'payment_collection_date' => $dateNow,
26416                    'card_company' => $cardCompany,
26417                    'payment_plan_id' => $paymentPlanId,
26418                    'membership_type_index' => $membershipStatusIndex
26419                ),
26420                array(
26421                    'PaymentReceivable.user_id' => $userId,
26422                    'PaymentReceivable.status' => 0,
26423                    'PaymentReceivable.payment_element_type' => Configure::read('appreciation_data.payment_element_type'),
26424                    'PaymentReceivable.created <=' => $cronDateRun
26425                )
26426            );
26427
26428            // create new live lesson payment receivable
26429            if ($formType != Configure::read('payment_live_lesson_receivable') && $liveLessonReceivable) {
26430                // set payment id
26431                $data["payment_id"] = $paymentId;
26432
26433                // set variables
26434                $paymentData = array(
26435                    'user_id' => $userId,
26436                    'type_id' => $typeId,
26437                    'reference_id' => $userId,
26438                    'status' => $paymentStatus,
26439                    'form_type' => Configure::read('payment_live_lesson_receivable'),
26440                    'ordd' => $orderCode,
26441                    'amount' => $liveLessonReceivable,
26442                    'param1' => $dataJson,
26443                    'card_company' => $cardCompany,
26444                    'transaction_code' => $orderCode,
26445                    'currency_code' => $currencyCode,
26446                    'payment_id' => $paymentPlanId,
26447                    'price_id' => $priceId,
26448                    'payment_type' => $paymentType,
26449                    'discounted_amount' => 0
26450                );
26451
26452                // create new payment
26453                $pModel->clear();
26454                $pModel->create();
26455                $pModel->validate = array();
26456                $pModel->set($paymentData);
26457
26458                if (!$pModel->save()) {
26459                    $msg = 'Saving payment receivable failed.';
26460                    $this->log(__METHOD__ . ' ' . $msg . ' Params --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, $logFileName);
26461                    $dataSource->rollback();
26462                    $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
26463                    throw new InternalErrorException($msg);
26464                }
26465                //update/add user`s settlement amount
26466                $this->User->updateUserPayments($paymentData);
26467                // set payment_id
26468                $paymentId = $pModel->id;
26469            }
26470
26471            // set payment receivable statuses to 2 - received
26472            $this->PaymentReceivable->updateReceivableReservationPayment(
26473                $userId, 
26474                array(
26475                    'status' => 2,
26476                    'payment_id' => $paymentId,
26477                    'payment_collection_date' => $dateNow,
26478                    'card_company' => $cardCompany,
26479                    'payment_plan_id' => $paymentPlanId,
26480                    'membership_type_index' => $membershipStatusIndex
26481                ),
26482                array(
26483                    'PaymentReceivable.user_id' => $userId,
26484                    'PaymentReceivable.status' => 0,
26485                    'PaymentReceivable.payment_element_type' => Configure::read('payment_element_type.live'),
26486                    'PaymentReceivable.created <=' => $cronDateRun
26487                )
26488            );    
26489        }
26490
26491
26492        // NC-7029: CHECK REFERRAL USER
26493        if (
26494            in_array($formType, array(
26495                Configure::read('payment_credit_monthly_payment'),
26496                Configure::read('payment_credit_force_charge'),
26497                Configure::read('payment_credit_retry'),
26498                Configure::read('payment_credit_authentication')
26499            ))
26500        ) {
26501            $ruData = array(
26502                'referee_id' => $userId,
26503                'payment_plan_id' => $paymentPlanId,
26504                'currency_code' => isset($userData['currency_code']) ? $userData['currency_code'] : Configure::read('pc_allowed_currencies.zh-tw'),
26505                'logFileName' => $logFileName,
26506                'form_type' => $formType
26507            );
26508
26509            $couponReferredData = $this->UsersReferral->checkReferredUser($ruData);
26510            if (isset($couponReferredData['error']) && $couponReferredData['error']) {
26511                $msg = 'Failed to update users referral event flg.';
26512                $this->log(__METHOD__ . ' ' . $msg . ' Params --> ' . json_encode($ruData) . ' | kickback data --> ' . $dataJson, $logFileName);
26513                $dataSource->rollback();
26514                $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
26515                throw new InternalErrorException($msg);
26516            }
26517
26518            $couponMailId = Configure::read('site_in_mail.coupon_mail_template_id');
26519
26520            // send coupon mail to referee
26521            if (isset($couponReferredData['sendMailToReferee']) && $couponReferredData['sendMailToReferee']) {
26522                $refereeData = array(
26523                    'id' => $userData['id'],
26524                    'email' => $userData['email'],
26525                    'native_language2' => $userData['native_language2'],
26526                    'hash' => $userData['hash'],
26527                    'refereeName' => $userData['nickname'],
26528                    'referrerName' => $couponReferredData['referrerName'],
26529                    'couponAmount' => $couponReferredData['refereeSaveAmount'],
26530                    'couponUpdatedTotal' => $couponReferredData['refereeUpdatedTotal']
26531                );
26532
26533                // send mail to referee
26534                myMailer::sendTemplateMail($couponMailId, $userData['email'], $refereeData, array(), 'User');
26535            }
26536
26537            // send coupon mail to referer
26538            if (isset($couponReferredData['sendMailToReferer']) && $couponReferredData['sendMailToReferer']) {
26539                $referrerData = array(
26540                    'id' => $couponReferredData['referrerId'],
26541                    'email' => $couponReferredData['referrerEmail'],
26542                    'native_language2' => $couponReferredData['nativeLanguage2'],
26543                    'hash' => $couponReferredData['referrerHash'],
26544                    'refereeName' => $userData['nickname'],
26545                    'referrerName' => $couponReferredData['referrerName'],
26546                    'couponAmount' => $couponReferredData['refererSaveAmount'],
26547                    'couponUpdatedTotal' => $couponReferredData['refererUpdatedTotal']
26548                );
26549
26550                // send mail to referrer
26551                myMailer::sendTemplateMail($couponMailId, $couponReferredData['referrerEmail'], $referrerData, array(), 'User');
26552            }
26553
26554            // NJ-47740
26555            if (!empty($ptPaymentParams['monthlyDiscount']) && !empty($ptPaymentParams['monthly_grp_id'])) {
26556                // confirm coupon use request for discount
26557                $requestCouponConfirmData = array(
26558                    'grpId' => $ptPaymentParams['coupon_request_id'],
26559                    'paymentId' => $paymentSaveID
26560                );
26561                $result_confirm = $this->UsersCouponV1->performCouponConfirm($requestCouponConfirmData);
26562                
26563                if (!$result_confirm) {
26564                    $this->log(__METHOD__ . ' Failed to confirm coupon use request. ' . json_encode($requestCouponConfirmData) . ' -- ' . $dataJson, $logFileName);
26565                    $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
26566                }
26567            }
26568            
26569            //update/add user`s settlement amount
26570            $this->User->updateUserPayments($paymentData);
26571        } 
26572
26573        // if has native speaker payment
26574        if (
26575            isset($ptPaymentParams['nativeOptionPayment']) && $ptPaymentParams['nativeOptionPayment'] > 0
26576            && in_array($ptPaymentParams['formType'], array(Configure::read('payment_credit_monthly_payment'), Configure::read('payment_credit_family_monthly_payment')))
26577        ) {
26578            $nspFormType = Configure::read('payment_native_option_monthly_payment');
26579
26580            // check if family plan
26581            if ($familyId && $parentId) {
26582                // change reference id to parent id
26583                $referenceId = $parentId;
26584            } else {
26585                $referenceId = $userId;
26586            }
26587
26588            $paymentData = array(
26589                'user_id' => $userId,
26590                'type_id' => $typeId,
26591                'reference_id' => $referenceId,
26592                'payment_transaction_password' => $ptPassword,
26593                'status' => $paymentStatus,
26594                'form_type' => $nspFormType,
26595                'ordd' => $orderCode,
26596                'amount' => $ptPaymentParams['nativeOptionPayment'],
26597                'param1' => $dataJson,
26598                'card_company' => $cardCompany,
26599                'transaction_code' => $orderCode,
26600                'currency_code' => $currencyCode,
26601                'payment_id' => $paymentPlanId,
26602                'price_id' => $priceId,
26603                'payment_type' => Configure::read('payment_types.native_option'),
26604                'discounted_amount' => $discounted_amount
26605            );
26606
26607            // create new payment
26608            $pModel->clear();
26609            $pModel->create();
26610            $pModel->validate = array();
26611            $pModel->set($paymentData);
26612
26613            if (!$pModel->save()) {
26614                $msg = 'Saving payment receivable failed.';
26615                $this->log(__METHOD__ . ' ' . $msg . ' Params --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, $logFileName);
26616                $dataSource->rollback();
26617                $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
26618                throw new InternalErrorException($msg);
26619            }
26620
26621            //update/add user`s settlement amount
26622            $this->User->updateUserPayments($paymentData);
26623        }
26624        
26625        // activate the user native option (new, resume, and monthly payment)
26626        if (isset($ptPaymentParams['nativeOptionPayment']) && $ptPaymentParams['nativeOptionPayment'] > 0) { 
26627            $this->log(__METHOD__ . ' NJ-2388 debug Payment Transaction Data: ' . json_encode($paymentTransactionData), 'native_option_debug');
26628            $this->User->userNativeOptionProcess(array('user_id' => $userId, 'type' => 'on'));
26629
26630            //NJ-2814 add logs
26631            if (isset($ptPaymentParams['nativeOptionJoin']) && $ptPaymentParams['nativeOptionJoin']) {
26632                $nativeStatus = 1; // subscribed
26633                $statusBefore = '';
26634            } else {
26635                $nativeStatus = 2; // Monthly Continue
26636                $statusBefore = 1;
26637            }
26638
26639            $optionLogParams = array(
26640                'user_id' => $userId,
26641                'platform' => $ptPaymentParams['platform'],
26642                'status' => $nativeStatus,
26643                'controller_name' => $this->request->params['controller'],
26644                'action_name' => $this->request->params['action'],
26645                'user_type' => 0, // user
26646                'option_before' => $statusBefore,
26647                'option_after' => 1,
26648                'option_before_name' => '',
26649                'option_after_name' => 'Native Unlimited Option',
26650                'payment_plan_id' => $paymentPlanId
26651            );
26652
26653            ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
26654
26655            // - save registration status step
26656            $stepKey = Configure::read('registration_steps.user_info_entry');
26657            $this->saveStep($userId, $stepKey);
26658        }
26659
26660        // update payment transaction payment id, status and response text
26661        $ptUpdate = $this->updatePaymentTransaction(array(
26662            'id' => $paymentTransactionData['id'],
26663            'fields' => array(
26664                'status' => 1, // done
26665                'payment_id' => $paymentId,
26666                'response_text' => $ptResponseText
26667            ),
26668            'logFileName' => $logFileName
26669        ));
26670
26671        if (!$ptUpdate) {
26672            $msg = 'Updating payment transaction failed.';
26673            $dataSource->rollback();
26674            $this->slackAfteePErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
26675            throw new InternalErrorException($msg);
26676        }
26677
26678        // final save
26679        $dataSource->commit();
26680
26681        // add registration bonus if user registration
26682        if (isset($ptPaymentParams['userRegister']) && $ptPaymentParams['userRegister']) {
26683            UsersPointHistoryTable::checkDailyBonus($userId);
26684            $params = array(
26685                "type" => 1, // kickback
26686                "userID" => $userId
26687            );
26688
26689            // add referral coin NC-9359
26690            $this->User->addReferralBonus($params);
26691
26692            $receiveBonus = UsersPointTable::checkIfUserReceiveBonusUponRegister($userId);
26693            if (!$receiveBonus && empty($userData['User']['complimentary_code'])) {
26694                UsersPointTable::giveBonusCoins(['userId' => $userId, 'triggerNo' => 1]);
26695            }
26696        }
26697
26698        // campaign master trigger 2
26699        if (
26700            $formType == Configure::read('payment_credit_monthly_payment') && 
26701            $userData['payment_plan_id'] == Configure::read('payment_plans.free_trial')
26702        ) {
26703            UsersPointTable::giveBonusCoins(['userId' => $userId, 'triggerNo' => 2]);
26704        }
26705
26706        // Teacher Perks : Student re-enroll
26707        if ( $formType == Configure::read('payment_credit_force_charge')) {
26708            ClassRegistry::init('TeacherPerksAccount')->reEnroll(['user_id' => $userId]);
26709        }
26710
26711        // campaign master trigger 5
26712        $this->retrial_confiscate_coins([
26713            'formType' => $formType,
26714            'paymentPlanId' => $paymentPlanId,
26715            'userId' => $userId
26716        ]);
26717
26718        // send event to adjust
26719        $adjustParams = array(
26720            'formType' => $formType,
26721            'statusBefore' => isset($ptPaymentParams['statusBefore']) ? $ptPaymentParams['statusBefore'] : null,
26722            'userId' => $userId
26723        );
26724        UserTable::sendEventToAdjust($adjustParams);
26725    }
26726
26727    /** 
26728     * Aftee slack error reporting
26729    */
26730    private function slackAfteePErrorPostMsg($paymentHash = '', $userId = '', $errMsg = '', $paymentStatus = '') {
26731        $mySlack = new mySlack();
26732        $mySlack->channel = myTools::checkChannel("#nc-aftee-fail", "#fdc-test-channel");
26733        $mySlack->username = "AFTEE ERROR REPORT";
26734        $mySlack->link_names = true;
26735        $mySlack->text = "```";
26736        $mySlack->text .= "payment_hash: {$paymentHash}\n";
26737        $mySlack->text .= "payment_status: {$paymentStatus}\n";
26738        $mySlack->text .= "user_id: {$userId}\n";
26739        $mySlack->text .= "error: {$errMsg}\n";
26740        $mySlack->text .= "```";
26741        $mySlack->sendSlack();
26742    }
26743
26744    /**
26745     * Aftee Modal Authentication
26746     * Save payment data and update membership type
26747     * handle payment transaction success from aftee modal
26748     */
26749    public function handleAfteeAuthenticationSuccess(){
26750        $this->autoRender = $this->autoLayout = false;
26751        $logFileName = isset($this->request->data['logFileName']) ? $this->request->data['logFileName'] : 'debug';
26752        $response = array();
26753
26754        // get post data
26755        if ($this->request->is('post')) {
26756            $data = $this->request->data;
26757        }
26758
26759        // if empty data
26760        if ( !isset($data) || !isset($data['success']) || 
26761            !isset($data['success']['authorization_result']) || 
26762            !isset($data['logFileName']) ||
26763            !isset($data['apiToken']) ||
26764            !isset($data['formType']) ||
26765            !isset($data['successUrl']) ||
26766            !isset($data['memKeyError']) ||
26767            !isset($data['referrer']) ||
26768            (
26769                empty(trim($data['apiToken'])) &&
26770                $data['apiToken'] !== 0 &&
26771                $data['apiToken'] !== '0'
26772            )
26773        ) {
26774            $this->log(__METHOD__ . ' Missing parameters. post data --> ' . json_encode($data), $logFileName);
26775            throw new BadRequestException("Missing parameter(s).");
26776        }
26777
26778        // merge post data
26779        $successData = $data['success'];
26780        $successData['authentication_token'] = $data['authentication_token'];
26781        $data = $successData;    
26782
26783        // set variables
26784        $orderCode = isset($data['shop_transaction_no']) && !empty($data['shop_transaction_no']) ? $data['shop_transaction_no'] : NULL;
26785        $data['OrderCode'] = $orderCode;
26786        $paymentStatusName = isset($data['authorization_result']) && !empty($data['authorization_result']) ? $data['authorization_result'] : '';
26787        $afteeTransactionIdentifier = isset($data['id']) && !empty($data['id']) ? $data['id'] : NULL;
26788        if (isset($data['related_transaction']) && !empty($data['related_transaction'])) {
26789            $afteeTransactionIdentifier = $data['related_transaction'];
26790        }
26791        $dataJson = json_encode($data);
26792
26793        // get payment transaction data 
26794        $paymentTransactionData = $this->PaymentTransaction->getAfteePaymentTransaction($orderCode);
26795
26796        // return if payment transaction does not exist
26797        if (!$paymentTransactionData) {
26798            $msg = 'Payment transaction does not exist.';
26799            $this->log(__METHOD__ . ' ' . $msg . ' kickback data -->' . $dataJson, 'aftee_debug');
26800            throw new InternalErrorException($msg);
26801        }
26802
26803        if (!isset($paymentTransactionData['user_id'])) {
26804            $msg = ' array key user_id does not exist.';
26805            $this->log(__METHOD__ . ' ' . $msg . ' kickback data -->' . $dataJson, 'aftee_debug');
26806            throw new InternalErrorException($msg);
26807            exit;
26808        }
26809
26810        // set variables
26811        $userId = $paymentTransactionData['user_id'];
26812        $cardCompany = Configure::read('card_company.aftee');
26813        $typeId = 1; // default
26814        $ptPaymentParams = json_decode($paymentTransactionData['payment_params'], true);
26815        $logFileName = isset($ptPaymentParams['logFileName']) ? $ptPaymentParams['logFileName'] : 'debug';
26816        $currencyCode = isset($ptPaymentParams['currencyCode']) ? $ptPaymentParams['currencyCode'] : null;
26817        $formType = $ptPaymentParams['formType'];
26818        $cronDateRun = isset($ptPaymentParams['cronDateRun']) ? $ptPaymentParams['cronDateRun'] : date('Y-m-d H:i:s');
26819        $familyId = isset($ptPaymentParams['familyId']) ? $ptPaymentParams['familyId'] : null;
26820        $userId = $familyId ? $familyId : $userId;
26821        $receivablePayment = $liveLessonReceivable = 0;
26822
26823        //remove user from currently paying users
26824        UserTable::removePayingUserFromMemcache($userId);
26825
26826        if (!isset($ptPaymentParams['paymentAmount'])) {
26827            $msg = 'Payment amount in payment transaction does not exist.';
26828            $this->log(__METHOD__ . ' ' . $msg . ' kickback data -->' . $dataJson . ' - ' . json_encode($ptPaymentParams), $logFileName);
26829            throw new InternalErrorException($msg);
26830            exit;
26831        }
26832
26833        $amount = $ptPaymentParams['paymentAmount'];
26834
26835        // set user model
26836        $uModel = $this->User;
26837
26838        // get user data
26839        $userData = $uModel->find('first', array(
26840            'fields' => array(
26841                'status',
26842                'nickname',
26843                'email',
26844                'hash',
26845                'memo',
26846                'parent_id',
26847                'next_charge_date',
26848                'complimentary_code',
26849                'payment_plan_id',
26850                'monthly_speaking_attended_flg',
26851                'monthly_speaking_business_attended_flg',
26852                'id',
26853                'hash16',
26854                'currency_code',
26855                'native_language2',
26856                'charge_flg',
26857                'fail_flg',
26858                'double_check_flg',
26859                'birthday',
26860                'native_option',
26861                'card_company',
26862                'card_token',
26863                'aftee_transaction_identifier'
26864            ),
26865            'conditions' => array('id' => $userId),
26866            'recursive' => -1
26867        ));
26868
26869        // return if user does not exist
26870        if (!$userData) {
26871            $msg = "User does not exist";
26872            $this->log(__METHOD__ . ' User does not exist. payment transaction data --> ' . json_encode($paymentTransactionData) . ' | kickback data --> ' . $dataJson, $logFileName);
26873            throw new InternalErrorException($msg);
26874        }
26875
26876        // NC-9168: if card auth and user's currency does not match with processed payment currency, update to correct currency
26877        if (!$userData['User']['currency_code']) {
26878            if ($formType == Configure::read('payment_credit_authentication') && $currencyCode != $userData['User']['currency_code']) {
26879                $uModel->validate = array();
26880                $uModel->read(array('currency_code'), $userId);
26881                $uModel->set(array('currency_code' => $currencyCode));
26882                $uModel->save();
26883                $this->log(__METHOD__ . ' Update to correct currency --> ' . $currencyCode . ' | userData -->' . json_encode($userData) . ' | kickback data --> ' . $dataJson, $logFileName);
26884            }
26885        }
26886
26887        // NC-5127: if family is withdrawn
26888        if ($formType == Configure::read('payment_credit_family_monthly_payment') && $this->memcache->get('deactivated-user-'.$userId)) {
26889            $msg = "User is withdrawn";
26890            $this->log(__METHOD__ . ' User is withdrawn. ' . json_encode($data), 'monthly_payment');
26891            throw new InternalErrorException($msg);
26892        }
26893
26894        # NC-8194: check null payment_plan_id and price_id
26895        if (
26896            (!isset($ptPaymentParams['paymentPlanId']) || $ptPaymentParams['paymentPlanId'] == null) ||
26897            (!isset($ptPaymentParams['priceId']) || $ptPaymentParams['priceId'] == null)
26898        ) {
26899            if ( $userData['User']['payment_plan_id'] && $userData['User']['price_id']) {
26900                $paymentPlanId = $userData['User']['payment_plan_id'];
26901                $priceId = $userData['User']['price_id'];
26902            } else {
26903                $defPlan = $this->PaymentPlanPrice->getDefaultPlan($userData['User']);
26904                $paymentPlanId = $defPlan['paymentPlanId'];
26905                $priceId = $defPlan['priceId'];
26906            }
26907
26908            $ptPaymentParams['paymentPlanId'] = $paymentPlanId;
26909            $ptPaymentParams['priceId'] = $priceId;
26910        }
26911
26912        $nativeOptionPayment = 0;
26913
26914        // if monthly payment, retry or force charge
26915        // check if user has receivable payment
26916        if (in_array($formType, array(
26917            Configure::read('payment_credit_monthly_payment'),
26918            Configure::read('payment_credit_force_charge'),
26919            Configure::read('payment_credit_retry'),
26920            Configure::read('payment_credit_family_monthly_payment')
26921        ))) {
26922            // compute receivable payments
26923            $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun);
26924
26925            // if has receivable payment
26926            // deduct said monthly settlement from the money sent to zeus
26927            if ($receivablePayment && $receivablePayment <= $amount) {
26928                // deduct from monthly payment
26929                $amount = $amount - $receivablePayment;
26930            }
26931
26932            // if has native speaker payments
26933            // deduct
26934            if (isset($ptPaymentParams['nativeOptionPayment']) && $ptPaymentParams['nativeOptionPayment'] > 0) {
26935                $nativeOptionPayment = $ptPaymentParams['nativeOptionPayment'];
26936                $amount -= $nativeOptionPayment;
26937            }
26938
26939            // compute appreciation receivable payments
26940            $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.appreciation'));
26941
26942            // if has receivable payment
26943            // deduct said monthly settlement from the money
26944            if ($appreciationReceivable && $appreciationReceivable <= $amount) {
26945                // deduct from monthly payment
26946                $amount = $amount - $appreciationReceivable;
26947            }
26948
26949            // compute live receivable payments
26950            $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.live'));
26951
26952            // if has receivable payment
26953            // deduct said monthly settlement from the money
26954            if ($liveLessonReceivable && $liveLessonReceivable <= $amount) {
26955                // deduct from monthly payment
26956                $amount = $amount - $liveLessonReceivable;
26957            }            
26958
26959        }
26960
26961        // Check receivables combine on `payment_credit_receivable` form type
26962        if( $formType == Configure::read('payment_credit_receivable') ) {
26963
26964            // compute appreciation receivable payments
26965            $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('appreciation_data.payment_element_type'));
26966
26967            // if has receivable payment
26968            // deduct said monthly settlement from the money
26969            if ($appreciationReceivable && $appreciationReceivable <= $amount) {
26970                // deduct from monthly payment
26971                $amount = $amount - $appreciationReceivable;
26972            }
26973
26974            // compute live receivable payments
26975            $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.live'));
26976
26977            if ($liveLessonReceivable && $liveLessonReceivable <= $amount) {
26978                // deduct from monthly payment
26979                $amount = $amount - $liveLessonReceivable;
26980            }            
26981
26982        }
26983
26984        // set transaction
26985        $dataSource = $uModel->getDataSource();
26986        $dataSource->begin();
26987
26988        // save settlement history for tracking
26989        $shData = array(
26990            'userId' => $userId,
26991            'params' => json_encode($data)
26992        );
26993
26994        if (!SettlementHistoryTable::add($shData)) {
26995            $msg = 'Saving user settlement history failed.';
26996            $this->log(__METHOD__ . ' ' . $msg . ' data --> ' . json_encode($shData) . ' | kickback data --> ' . $dataJson, $logFileName);
26997            $dataSource->rollback();
26998            // $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
26999            throw new InternalErrorException($msg);
27000        }
27001
27002        $this->loadModel("ContinuationCampaign");
27003
27004        switch($paymentStatusName) {
27005            case Configure::read('aftee.payment_status_authorised'):
27006
27007                $afteeParams = array(
27008                    'data' => $data,
27009                    'ptData' => $paymentTransactionData,
27010                    'logFileName' => $logFileName,
27011                    'dataSource' => $dataSource,
27012                    'amount' => $amount,
27013                    'userData' => $userData,
27014                    'cronDateRun' => $cronDateRun,
27015                    'receivablePayment' => $receivablePayment,
27016                    'appreciationReceivable' => $appreciationReceivable,
27017                    'liveLessonReceivable' => $liveLessonReceivable,
27018                    'transactionIdentifier' => $afteeTransactionIdentifier,
27019                    'aftee' => 1
27020                );
27021
27022                if( $formType == Configure::read('payment_credit_authentication') ) {
27023
27024                    //NJ-7548: fetch the user age $userData
27025                    $uAge = UserTable::getStudentAge($userData['User']['birthday']);
27026                    $uAge = $uAge ? (int) $uAge : null;
27027                    $showAppreciationFlg = 0;
27028
27029                    //change the show appreciation flg if no birthday set or 18 and above            
27030                    if (!$uAge || $uAge >= 18) {
27031                        $showAppreciationFlg = 1;
27032                    }
27033
27034                    // set user data
27035                    $uModel->clear();
27036                    $uModel->recursive = -1;
27037                    $userSet = array( 'allow_appreciation_flg' => 1 , 'show_appreciation_flg' => $showAppreciationFlg);
27038
27039                    // set child card expiration date same as parent
27040                    if (isset($ptPaymentParams['family_data']['applyPlan']['card_expiration_date'])) {
27041                        $userSet['card_expiration_date'] = $ptPaymentParams['family_data']['applyPlan']['card_expiration_date'];
27042                    }
27043
27044                    $uModel->read(array_keys($userSet), $userId);
27045                    $uModel->set($userSet);
27046                    $uModel->validate = array();
27047                    if (!$uModel->save()) {
27048                        $msg = 'Updating user failed.';
27049                        $this->log(__METHOD__ . ' ' . $msg . ' data --> ' . json_encode($userSet) . ' | kickback data --> ' . $dataJson, $logFileName);
27050                        $dataSource->rollback();
27051                        // $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
27052                        throw new InternalErrorException($msg);
27053                    }
27054
27055                }
27056                // NJ-24425: release secured budget upon changing payment method FROM old AFTEE to new AFTEE number
27057                if ($formType == Configure::read('payment_credit_change')  
27058                    && !empty($userData['User']['card_token']) && !empty($userData['User']['aftee_transaction_identifier'])
27059                ) {
27060                    // check if user is still Free (no monthly payment made yet)
27061                    if ($userData['User']['payment_plan_id'] == Configure::read('payment_plans.free_trial')) {
27062                        if (!class_exists('AfteePaymentService')) {
27063                            App::uses('AfteePaymentService','Lib');
27064                        }
27065                        $afteeService = new AfteePaymentService();
27066                        $checkRes = $afteeService->refund($userData, 'Change Payment Method');
27067                        $this->log( '[NJ-24425] ' . json_encode($checkRes), 'aftee_debug');
27068                        if ( !array_key_exists("object", $checkRes) || (isset($checkRes['object']) && $checkRes['object'] == 'error')) {
27069                            $msg = '[Aftee] Failed to release secured budget';
27070                            $this->log(__METHOD__ . ' ' . $msg . ' User data --> ' . json_encode($userData) . ' | refundData --> ' . $checkRes, 'aftee_debug');
27071                        }
27072                    }
27073                }
27074                return $this->processAfteePayment($afteeParams);
27075            case Configure::read('aftee.payment_status_error'):
27076                switch ($formType) {
27077                    case Configure::read('payment_credit_family_monthly_payment'):
27078                    case Configure::read('payment_credit_monthly_payment'):
27079                        // set user data
27080                        $uModel->clear();
27081                        $uModel->recursive = -1;
27082                        $userSet = array(
27083                            'fail_flg' => 1,
27084                            'counseling_attended_flg' => 1,
27085                            'charge_flg' => 0,
27086                            'show_appreciation_flg' =>  0,
27087                            'allow_appreciation_flg' => 0,
27088                            'native_option' => 0,
27089                            'next_charge_date' => null,
27090                            'modified' => date('Y-m-d H:i:s')
27091                        );
27092
27093                        if (isset($userData['User']['native_option']) && $userData['User']['native_option']) {
27094                            $userSet['native_option_cancellation_time'] = date('Y-m-d H:i:s');
27095                        }
27096
27097                        $uModel->read(array_keys($userSet), $userId);
27098                        $memoStr = date('Y/m/d H:i:s')." Cancellation of Native Speaker Unlimited option";
27099                        $updatedMemo = $memoStr."\n".$userData['User']['memo'];
27100                        $userSet['memo'] = $updatedMemo;
27101
27102                        $uModel->set($userSet);
27103                        $uModel->validate = array();
27104                        if (!$uModel->save()) {
27105                            $msg = 'Updating user failed.';
27106                            $this->log(__METHOD__ . ' ' . $msg . ' data --> ' . json_encode($userSet) . ' | kickback data --> ' . $dataJson, $logFileName);
27107                            $dataSource->rollback();
27108                            // $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
27109                            throw new InternalErrorException($msg);
27110                        }
27111
27112                        //NJ-2814 add logs
27113                        if (isset($ptPaymentParams['nativeOptionJoin']) && $ptPaymentParams['nativeOptionJoin']) {
27114                            $nativeStatus = 1; // subscribed
27115                            $statusBefore = $option_before_name = '';
27116                        } else {
27117                            $nativeStatus = 3; // unsubscribed
27118                            $statusBefore = 1;
27119                            $option_before_name = 'Native Unlimited Option';
27120                        }
27121
27122                        $optionLogParams = array(
27123                            'user_id' => $userId,
27124                            'platform' => $ptPaymentParams['platform'],
27125                            'status' => $nativeStatus,
27126                            'controller_name' => $this->request->params['controller'],
27127                            'action_name' => $this->request->params['action'],
27128                            'user_type' => 0, // user
27129                            'option_before' => $statusBefore,
27130                            'option_after' => 1,
27131                            'option_before_name' => $option_before_name,
27132                            'option_after_name' => '',
27133                            'payment_plan_id' => $paymentPlanId
27134                        );
27135
27136                        ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
27137
27138                        // update user who join in ContinuationCampaign to fail status - 3
27139                        if ($this->ContinuationCampaign->setFailedUser(array('user_id' => $userId))) {
27140                            $msg = 'Failed to update ContinuationCampaign status to 3.';
27141                            $this->log(__METHOD__ . ' ' . $msg . ' data --> ' . json_encode(array('user_id' => $userId)) . ' | kickback data --> ' . $dataJson, $logFileName);
27142                            $dataSource->rollback();
27143                            // $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
27144                            throw new InternalErrorException($msg);
27145                        }
27146
27147                        // Get children list
27148                        $childList = $uModel->getChildId($userId);
27149
27150                        // check if user is parent 
27151                        if (!empty($childList)) {
27152                            foreach ($childList as $childId) {
27153                                // get child detail
27154                                $familyMember = $uModel->find('first', array(
27155                                    'fields' => array(
27156                                        'User.id',
27157                                        'User.memo',
27158                                        'User.parent_id',
27159                                        'User.native_option'
27160                                    ),
27161                                    'conditions' => array('User.id' => $childId)
27162                                ));
27163                                $familyObj = new UserTable($familyMember['User']);
27164                                $addMemo = 'Family plan[User]: family deactivation parent failed settlement';
27165                                unset($familyObj->parent_id);
27166
27167                                // update children status to free
27168                                if ($this->User->updateStatusToFree($familyObj, $addMemo)) {
27169                                    // - deactivate reserved lessons of the children
27170                                    $this->LessonSchedule->deactivateDisableReservedLessons($childId, true, false, true, null, false, true);
27171
27172                                    // NC-8645: add deactivation lock
27173                                    UserTable::saveUserDeactivationLock($childId);
27174
27175                                    // NC-5342: add deactivation log
27176                                    $this->loadModel('FamilyDeactivationLog');
27177                                    $this->FamilyDeactivationLog->addLog($childId);
27178                                }
27179
27180                                $switchAccountParams = array(
27181                                    'parentId' => $userId,
27182                                    'userId' => $childId
27183                                );
27184                                // delete switch account data
27185                                $this->UsersFamilyAccount->removeSwitchAccount($switchAccountParams);
27186                            }
27187                        }
27188
27189                        if ($nativeOptionPayment > 0) {
27190                            $paymentNOData = array(
27191                                'user_id' => $userId,
27192                                'type_id' => $typeId,
27193                                'pay_kbn' => 1,
27194                                'form_type' => Configure::read('payment_native_option_monthly_payment'),
27195                                'reference_id' => $userId,
27196                                'amount' => $nativeOptionPayment,
27197                                'ordd' => $orderCode,
27198                                'card_company' => $cardCompany,
27199                                'param1' => $dataJson,
27200                                'param2' => 'error: aftee',
27201                                'transaction_code' => $orderCode,
27202                                'currency_code' => $currencyCode,
27203                                'payment_plan_id' => isset($ptPaymentParams['paymentPlanId']) ? $ptPaymentParams['paymentPlanId'] : null,
27204                                'price_id' => isset($ptPaymentParams['priceId']) ? $ptPaymentParams['priceId'] : null,
27205                                'payment_type' => isset($ptPaymentParams['paymentType']) ? $ptPaymentParams['paymentType'] : null,
27206                                'discounted_amount' => isset($ptPaymentParams['discounted_amount']) ? $ptPaymentParams['discounted_amount'] : 0
27207                            );
27208
27209                            // set payment model
27210                            $pModel = $this->Payment;
27211                            $pModel->clear();
27212                            $pModel->create();
27213                            $pModel->recursive = -1;
27214                            $pModel->set($paymentNOData);
27215                            $pModel->validate = array();
27216
27217                            if (!$pSave = $pModel->save()) {
27218                                $msg = 'Saving payment failed.';
27219                                $this->log(__METHOD__ . ' ' . $msg . ' data --> ' . json_encode($paymentNOData) . ' | kickback data --> ' . $dataJson, $logFileName);
27220                                $dataSource->rollback();
27221                                // $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
27222                                throw new InternalErrorException($msg);
27223                            }
27224                        }
27225                    case Configure::read('payment_credit_receivable'):
27226                    case Configure::read('payment_credit_retry'):
27227                    case Configure::read('payment_credit_force_charge'):
27228                        $paymentData = array(
27229                            'user_id' => $userId,
27230                            'type_id' => $typeId,
27231                            'pay_kbn' => 1,
27232                            'form_type' => $formType,
27233                            'reference_id' => $userId,
27234                            'amount' => $amount,
27235                            'ordd' => $orderCode,
27236                            'card_company' => $cardCompany,
27237                            'param1' => $dataJson,
27238                            'param2' => 'error: aftee',
27239                            'transaction_code' => $orderCode,
27240                            'currency_code' => $currencyCode,
27241                            'payment_plan_id' => isset($ptPaymentParams['paymentPlanId']) ? $ptPaymentParams['paymentPlanId'] : null,
27242                            'price_id' => isset($ptPaymentParams['priceId']) ? $ptPaymentParams['priceId'] : null,
27243                            'payment_type' => isset($ptPaymentParams['paymentType']) ? $ptPaymentParams['paymentType'] : null,
27244                            'discounted_amount' => isset($ptPaymentParams['discounted_amount']) ? $ptPaymentParams['discounted_amount'] : 0
27245                        );
27246
27247                        // set payment model
27248                        $pModel = $this->Payment;
27249                        $pModel->clear();
27250                        $pModel->create();
27251                        $pModel->recursive = -1;
27252                        $pModel->set($paymentData);
27253                        $pModel->validate = array();
27254
27255                        if (!$pSave = $pModel->save()) {
27256                            $msg = 'Saving payment failed.';
27257                            $this->log(__METHOD__ . ' ' . $msg . ' data --> ' . json_encode($paymentData) . ' | kickback data --> ' . $dataJson, $logFileName);
27258                            $dataSource->rollback();
27259                            // $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
27260                            throw new InternalErrorException($msg);
27261                        }
27262                    case Configure::read('payment_credit_authentication'):
27263                    case Configure::read('payment_credit_change'):
27264                        $ptUpdate = $this->updatePaymentTransaction(array(
27265                            'id' => $paymentTransactionData['id'],
27266                            'fields' => array(
27267                                'status' => 2, // error
27268                                'payment_id' => isset($pSave['Payment']['id']) ? $pSave['Payment']['id'] : null,
27269                                'response_text' => array('aftee_kickback' => json_decode($dataJson, true))
27270                            ),
27271                            'logFileName' => $logFileName
27272                        ));
27273
27274                        if (!$ptUpdate) {
27275                            $dataSource->rollback();
27276                            $msg = 'Updating payment transaction failed.';
27277                            $this->log(__METHOD__ . ' ' . $msg . ' data --> ' . json_encode(array('pt_id' => $paymentTransactionData['id'])) . ' | kickback data --> ' . $dataJson, $logFileName);
27278                            // $this->slackWPErrorPostMsg($orderCode, $userId, $msg, $paymentStatusName);
27279                            throw new InternalErrorException($msg);
27280                        }
27281                        break;
27282                }
27283                $dataSource->commit();
27284                break;
27285            default:
27286                $this->log(__METHOD__ . ' No data save', $logFileName);
27287                break;
27288        }
27289        $response['success'] = true;
27290        return json_encode($response);
27291    }
27292
27293    /**
27294     * Aftee Modal Direct Payment outside membership
27295     * Save payment data for coin, native option, ebook
27296     * handle payment transaction success from aftee modal
27297     */
27298    public function handleAfteeDirectPaymentSuccess(){
27299        $this->autoRender = $this->autoLayout = false;
27300        $logFileName = isset($this->request->data['logFileName']) ? $this->request->data['logFileName'] : 'debug';
27301        $ncTerminalType = isset($this->request->data['ncTerminalType']) ? $this->request->data['ncTerminalType'] : 1;
27302        $response = array();
27303
27304        // get post data
27305        if ($this->request->is('post')) {
27306            $rawData = $data = $this->request->data;
27307        }
27308
27309        // if empty data
27310        if ( !isset($data) || !isset($data['success']) || 
27311            !isset($data['success']['authorization_result']) || 
27312            !isset($data['logFileName']) ||
27313            !isset($data['apiToken']) ||
27314            !isset($data['formType']) ||
27315            !isset($data['successUrl']) ||
27316            !isset($data['memKeyError']) ||
27317            !isset($data['referrer']) ||
27318            (
27319                empty(trim($data['apiToken'])) &&
27320                $data['apiToken'] !== 0 &&
27321                $data['apiToken'] !== '0'
27322            )
27323        ) {
27324            $this->log(__METHOD__ . ' Missing parameters. post data --> ' . json_encode($data), 'error');
27325            throw new BadRequestException("Missing parameter(s).");
27326        }
27327
27328        // merge post data
27329        $successData = $data['success'];
27330        $successData['authentication_token'] = $data['authentication_token'];
27331        $data = $successData;    
27332
27333        // set variables
27334        $orderCode = isset($data['shop_transaction_no']) && !empty($data['shop_transaction_no']) ? $data['shop_transaction_no'] : NULL;
27335        $data['OrderCode'] = $orderCode;
27336        $paymentStatusName = isset($data['authorization_result']) && !empty($data['authorization_result']) ? $data['authorization_result'] : '';
27337        $dataJson = json_encode($data);
27338        $device = myTools::getDevice();
27339        if ($ncTerminalType == Configure::read('nc_terminal_type.pc')) {
27340            if ($device != 1) {
27341                $device = 6; // sp
27342            }
27343        }
27344
27345        // get payment transaction data 
27346        $paymentTransactionData = $this->PaymentTransaction->getAfteePaymentTransaction($orderCode);
27347        $pt = $paymentTransactionData;
27348
27349        // return if payment transaction does not exist
27350        if (!$paymentTransactionData) {
27351            $msg = 'Payment transaction does not exist.';
27352            $this->log(__METHOD__ . ' ' . $msg . ' kickback data -->' . $dataJson, 'aftee_debug');
27353            throw new InternalErrorException($msg);
27354        }
27355
27356        if (!isset($paymentTransactionData['user_id'])) {
27357            $msg = ' array key user_id does not exist.';
27358            $this->log(__METHOD__ . ' ' . $msg . ' kickback data -->' . $dataJson, 'aftee_debug');
27359            throw new InternalErrorException($msg);
27360            exit;
27361        }
27362
27363        // set variables
27364        $userId = $paymentTransactionData['user_id'];
27365        $cardCompany = Configure::read('card_company.aftee');
27366        $ptPaymentParams = json_decode($paymentTransactionData['payment_params'], true);
27367        $logFileName = isset($ptPaymentParams['logFileName']) ? $ptPaymentParams['logFileName'] : 'debug';
27368        $currencyCode = isset($ptPaymentParams['currencyCode']) ? $ptPaymentParams['currencyCode'] : '';
27369        $formType = $ptPaymentParams['formType'];
27370        $familyId = isset($ptPaymentParams['familyId']) ? $ptPaymentParams['familyId'] : null;
27371        $userId = $familyId ? $familyId : $userId;
27372
27373        //remove user from currently paying users
27374        UserTable::removePayingUserFromMemcache($userId);
27375
27376        if (!isset($ptPaymentParams['paymentAmount'])) {
27377            $msg = 'Payment amount in payment transaction does not exist.';
27378            $this->log(__METHOD__ . ' ' . $msg . ' kickback data -->' . $dataJson . ' - ' . json_encode($ptPaymentParams), 'error');
27379            throw new InternalErrorException($msg);
27380            exit;
27381        }
27382
27383        $amount = $ptPaymentParams['paymentAmount'];
27384
27385        // set user model
27386        $uModel = $this->User;
27387
27388        // get user data
27389        $user = $uModel->find('first', array(
27390            'fields' => array(
27391                'status',
27392                'nickname',
27393                'email',
27394                'hash',
27395                'memo',
27396                'parent_id',
27397                'next_charge_date',
27398                'complimentary_code',
27399                'payment_plan_id',
27400                'monthly_speaking_attended_flg',
27401                'monthly_speaking_business_attended_flg',
27402                'id',
27403                'hash16',
27404                'currency_code',
27405                'native_language2',
27406                'charge_flg',
27407                'fail_flg',
27408                'double_check_flg',
27409                'birthday',
27410                'native_option',
27411                'phone_number',
27412                'callan_first_name',
27413                'callan_last_name',
27414                'callan_gender'
27415            ),
27416            'conditions' => array('id' => $userId),
27417            'recursive' => -1
27418        ));
27419        
27420
27421        // return if user does not exist
27422        if (!$user) {
27423            $msg = "User does not exist";
27424            $this->log(__METHOD__ . ' User does not exist. payment transaction data --> ' . json_encode($paymentTransactionData) . ' | kickback data --> ' . $dataJson, $logFileName);
27425            throw new InternalErrorException($msg);
27426        }
27427
27428        $userData = $user['User'];
27429
27430
27431        switch ($formType) {
27432            case Configure::read('payment_credit_coin_purchase'):
27433                $money = $amount;
27434                $points = isset($ptPaymentParams['coinPurchasePoints']) ? $ptPaymentParams['coinPurchasePoints'] : 0;
27435                $couponAmount = isset($ptPaymentParams['discounted_amount']) ? $ptPaymentParams['discounted_amount'] : 0;
27436                $paymentPlanId = isset($ptPaymentParams['paymentPlanId']) ? $ptPaymentParams['paymentPlanId'] : '';
27437                $priceId = isset($ptPaymentParams['priceId']) ? $ptPaymentParams['priceId'] : '';
27438                $paymentType = Configure::read('payment_types.coin');
27439                $coinPurchaseWithCoupon = false;
27440                if ($paymentStatusName == Configure::read('aftee.payment_status_authorised')) {
27441                    
27442                    if (!class_exists('myMemcached')) {
27443                        App::uses('myMemcached', 'Lib');
27444                    }
27445                    $memcached = new myMemcached();
27446                    
27447                    //check if coupon requests is processed already
27448                    $isCouponRequestId = $memcached->get('aftee_coupon_used_' . $userId);
27449
27450                    // if using coupon
27451                    $couponReqID = null;
27452                    if(isset($isCouponRequestId['success']) && $isCouponRequestId['success']) {
27453                        $couponReqID = isset($isCouponRequestId['grp_id']) ? $isCouponRequestId['grp_id'] : null;
27454                        $coinPurchaseWithCoupon = true;
27455                        $memcached->delete('aftee_coupon_used_' . $userId);
27456                    } else {
27457                        if ($couponAmount > 0) {
27458                            $couponData = array(
27459                                'userId' => $userId,
27460                                'kbn' => isset($ptPaymentParams['coin_event']) ? $ptPaymentParams['coin_event'] : Configure::read('coupon_kbn.coin_purchase'),
27461                                'useCouponAmount' => isset($ptPaymentParams['coin_useCouponAmount']) ? $ptPaymentParams['coin_useCouponAmount'] : 0,
27462                                'nextChargeDate' => date('Y-m-d'),
27463                                'request_result' => true
27464                            );
27465                            // TEMPLATE
27466                            $result_coupon_use = $this->UsersCouponV1->performCouponUse($couponData);
27467                            $result_coupon_use = !empty($result_coupon_use) ? json_decode($result_coupon_use,true) : array();
27468                            if(empty($result_coupon_use)) {
27469                                $this->log(__METHOD__ . ' failed to update coupon data. --> ' . json_encode($couponData) . ' user id --> ' . json_encode($userData['id']), 'error');
27470                                $msg = Configure::read('Coin purchased failed');
27471                                throw new InternalErrorException($msg);
27472                                exit;
27473                            }
27474
27475                            if (isset($result_coupon_use['cgrp_id'])) {
27476                                $coinPurchaseWithCoupon = true;
27477                                $couponReqID = $result_coupon_use['cgrp_id'];
27478                            }
27479                        }
27480                    }
27481
27482                    $referenceId = (isset($userData['parent_id']) && !empty($userData['parent_id'])) ? $userData['parent_id'] : $userId;
27483                    $coinPurchasePoints = intVal($points);
27484                    $coinData = $this->UsersPoint->SET_charge_overseas_menue($coinPurchasePoints, $currencyCode);
27485
27486                    // NC-5007 add to the user's existing coin
27487                    $pcAfteeParams = array(
27488                        'userId' => $userId,
27489                        'point' => $coinData['num_of_coin'] - $coinData['bonus_coin'],
27490                        'kbn' => 7,
27491                        'kbnType' => 1, // add coin
27492                        'coinType' => 1, // purchase coin
27493                        'coinFailMessage' => Configure::read('coin.failed.buy_coin'),
27494                        'device' => $device
27495                    );
27496
27497                    $scAfteeParams = array(
27498                        'userId' => $userId,
27499                        'point' => $coinData['bonus_coin'],
27500                        'kbn' => 7,
27501                        'kbnType' => 1, // add coin
27502                        'coinType' => 2, // service coin
27503                        'coinFailMessage' => Configure::read('coin.failed.buy_coin'),
27504                        'device' => $device
27505                    );
27506
27507                    $pointParams = [$pcAfteeParams, $scAfteeParams];
27508
27509                    if ( $pointParams ) {
27510                        foreach($pointParams as $key => $val) {
27511                            if (!$this->UsersPoint->performPointTransaction($val)) {
27512                                $this->log(__METHOD__ . ' Failed to add user point. ' . json_encode($val) . ' --> ' . json_encode($paymentTransactionData), 'error');
27513                                $msg = Configure::read('Coin purchased failed');
27514                                throw new InternalErrorException($msg);
27515                                exit;
27516                            }
27517                        }
27518                    }
27519                    
27520                    $paymentData = array(
27521                        'user_id' => $userId,
27522                        'amount' => $money,
27523                        'status' => 1,
27524                        'reference_id' => $referenceId,
27525                        'payment_transaction_password' => $pt['password'],
27526                        'card_company' => Configure::read('card_company.aftee'),
27527                        'param1' => json_encode($data),
27528                        'form_type' => $formType,
27529                        'ordd' => $orderCode,
27530                        'transaction_code' => $orderCode,
27531                        'currency_id' => Configure::read('default.settlement_currency_id'), // set currency id to jpy
27532                        'currency_code' => $currencyCode,
27533                        'payment_id' => $paymentPlanId,
27534                        'price_id' => $priceId,
27535                        'payment_type' => $paymentType,
27536                        'discounted_amount' => $couponAmount,
27537                        'coupon_request_id' => $couponReqID,
27538                        'type_id' => 1
27539                    );
27540
27541                    // create new payment
27542                    $this->Payment->clear();
27543                    $this->Payment->create();
27544                    $this->Payment->set($paymentData);
27545                    $this->Payment->validate = array();
27546
27547                    // check if payment was not saved
27548                    if (!$this->Payment->save()) {
27549                        $this->log(__METHOD__ . ' Failed to save payment data. ' . json_encode($paymentData) . ' -- ' . json_encode($data), $logFileName);
27550
27551                        if($coinPurchaseWithCoupon) {
27552                            $couponUnconfirmData = array(
27553                                'grpId' => $paymentData['coupon_request_id'],
27554                                'userId' => $userId,
27555                                'kbn' => Configure::read('coupon_kbn.coin_purchase')
27556                            );
27557                            $result_coupon_unconfirm = $this->UsersCouponV1->performCouponUnconfirm($couponUnconfirmData);
27558                            
27559                            if (empty($result_coupon_unconfirm)) {
27560                                $this->log(__METHOD__ . ' failed to perform coupon unconfirm data. '. json_encode($couponUnconfirmData), 'error');
27561                            }
27562                        }
27563
27564                        $msg = 'Coin purchased failed';
27565                        throw new InternalErrorException($msg);
27566                        exit;
27567                    }
27568
27569                    //update/add user`s settlement amount
27570                    $this->User->updateUserPayments($paymentData);
27571
27572                    // update payment transaction
27573                    $updateData = array(
27574                        'id' => $pt['id'],
27575                        'fields' => array(
27576                            'status' => 1,
27577                            'response_text' => array('aftee_directPayment_response' => $data))
27578                    );
27579
27580                    // update payment transaction
27581                    if (!$this->PaymentTransaction->updateAfteePaymentTransaction($updateData)) {
27582                        $this->log(__METHOD__ . ' Failed to save payment data. ' . json_encode($paymentData) . ' -- ' . json_encode($data), $logFileName);
27583                        $msg = Configure::read('Coin purchased failed');
27584                        throw new InternalErrorException($msg);
27585                    }
27586                    
27587                } else if ($paymentStatusName ==  Configure::read('aftee.payment_status_error')) {
27588                    $afteeParams = array(
27589                        'ptId' => $pt['id'],
27590                        'afteeData' => array('aftee_directpayment_response' => $data),
27591                        'userId' => $userId,
27592                        'money' => $money,
27593                        'formType' => $formType,
27594                        'priceId' => $priceId,
27595                        'paymentId' => $paymentPlanId,
27596                        'paymentType' => $paymentType,
27597                        'currency' => $currencyCode
27598                    );
27599                    $this->Payment->afteeSaveFailedSettlement($afteeParams);
27600                    $this->log(__METHOD__ . ' Failed to save payment data. ' . json_encode($paymentData) . ' -- ' . json_encode($data), $logFileName);
27601                    $msg = Configure::read('Coin purchased failed');
27602                    throw new InternalErrorException($msg);
27603                }
27604                break;
27605            case Configure::read('payment_credit_textbook_purchase'):
27606                $money = isset($ptPaymentParams['money']) ? $ptPaymentParams['money'] : 0;
27607                $discounted_amount = isset($ptPaymentParams['discounted_amount']) ? $ptPaymentParams['discounted_amount'] : 0;
27608                $formType = Configure::read('payment_credit_textbook_purchase');
27609                $paymentType = Configure::read('payment_types.textbook_purchase');
27610                if ($paymentStatusName == Configure::read('aftee.payment_status_authorised')) {
27611                    $textbookItems = isset($ptPaymentParams['textbookItems']) ? $ptPaymentParams['textbookItems'] : array();
27612                    $subTotal = isset($ptPaymentParams['subTotal']) ? $ptPaymentParams['subTotal'] : '';
27613                    $textbook_sales_id = isset($rawData['textbook_sales_id']) ? $rawData['textbook_sales_id'] : '';
27614                    $referenceId = isset($userData['parent_id']) && !empty($userData['parent_id']) ? $userData['parent_id'] : $userData['id'];
27615                    $paymentData = array(
27616                        'user_id' => $userData['id'],
27617                        'amount' => $money,
27618                        'status' => 1,
27619                        'reference_id' => $referenceId,
27620                        'payment_transaction_password' => $pt['password'],
27621                        'card_company' => Configure::read('card_company.aftee'),
27622                        'param1' => json_encode($data),
27623                        'form_type' => $formType,
27624                        'ordd' => $orderCode,
27625                        'transaction_code' => $orderCode,
27626                        'currency_id' => Configure::read('default.settlement_currency_id'), // set currency id to jpy
27627                        'currency_code' => $userData['currency_code'],
27628                        'payment_id' => $userData['payment_plan_id'],
27629                        'price_id' => $userData['price_id'],
27630                        'payment_type' => $paymentType,
27631                        'type_id' => 1,
27632                        'discounted_amount' => $discounted_amount
27633                    );
27634            
27635                    // create new payment
27636                    $this->Payment->clear();
27637                    $this->Payment->create();
27638                    $this->Payment->set($paymentData);
27639                    $this->Payment->validate = array();
27640            
27641                    // check if payment was not saved
27642                    if (!$this->Payment->save()) {
27643                        $this->log(__METHOD__ . ' Failed to save payment data. ' . json_encode($paymentData), $logFileName);
27644                        $msg = 'failed_to_save_payment_data';
27645                        throw new InternalErrorException($msg);
27646                    }
27647            
27648                    //update/add user`s settlement amount
27649                    $this->User->updateUserPayments($paymentData);
27650            
27651                    $textbookSales = $this->TextbookSale->find('first', array(
27652                        'conditions' => array('TextbookSale.sales_code' => $pt['password']),
27653                        'recursive' => -1
27654                    ));
27655            
27656                    // if has textbook sales, update payment_id
27657                    if ($textbookSales) {
27658                        $this->TextbookSale->clear();
27659                        if (!$this->TextbookSale->read(null, $textbookSales['TextbookSale']['id'])) {
27660                            $this->log(__METHOD__ . ' Textbook sales id does not exist. ' . json_encode($textbookSales), $logFileName);
27661                            $msg = 'textbook_sales_id_does_not_exist';
27662                            throw new InternalErrorException($msg);
27663                        }
27664            
27665                        $this->TextbookSale->set('payment_id', $this->Payment->id);
27666                        $this->TextbookSale->set('payment_status', 1);
27667                        if (!$this->TextbookSale->save()) {
27668                            $this->log(__METHOD__ . ' Failed update textbook sales payment status to 1. ' . json_encode($textbookSales), $logFileName);
27669                            $msg = 'failed_update_textbook_sales_payment_status_to_1';
27670                            throw new InternalErrorException($msg);
27671                        }
27672                    }
27673
27674                    // update payment transaction
27675                    $updateData = array(
27676                        'id' => $pt['id'],
27677                        'fields' => array(
27678                            'status' => 1,
27679                            'response_text' => array('aftee_directPayment_response' => $data))
27680                    );
27681
27682                    // update payment transaction
27683                    if (!$this->PaymentTransaction->updateAfteePaymentTransaction($updateData)) {
27684                        $this->log(__METHOD__ . ' Failed to save payment data. ' . json_encode($paymentData) . ' -- ' . json_encode($data), $logFileName);
27685                        $msg = Configure::read('Coin purchased failed');
27686                        throw new InternalErrorException($msg);
27687                    }
27688                    
27689                    // on sucess send email
27690                    // and send to slack
27691
27692                    // get items
27693                    $cartItems = array();
27694                    $totalCartItems = count($textbookItems);
27695                    $countNatGeoEbookItems = 0;
27696                    // loop through items
27697                    foreach ($textbookItems as $cart) {
27698                        if(!empty($cart['title'])) {
27699                            $cartIds[] = $cart['id'];
27700                            $cartItems[] = $cart['title'];
27701
27702                            //NC-7469 for nat geo ebbok items
27703                            if ($cart['category_id'] == Configure::read('national_geographic_ebook')) {
27704                                $countNatGeoEbookItems += 1;
27705                            }
27706                        }
27707                    }
27708
27709                    // NJ-18619: update add to cart status
27710                    if ($textbookItems) {
27711                        $this->TextbookSalesAddToCartItem->clear();
27712                           $conditions = array(
27713                               'TextbookSalesAddToCartItem.user_id' => $userData['id'],
27714                               'TextbookSalesAddToCartItem.status' => 1
27715                           );
27716                        $this->TextbookSalesAddToCartItem->updateAll(
27717                            array(
27718                                'TextbookSalesAddToCartItem.status' => 0
27719                            ),
27720                            $conditions
27721                        );
27722                    }
27723
27724                    $post['totalNatGeoEbookItems'] = $countNatGeoEbookItems;
27725
27726                    // get genders
27727                    $callanGender = Configure::read('gender_types');
27728
27729                    // set template id for email sending
27730                    $post['templateId'] = Configure::read('site_in_mail.student_ebook_purchase_complete');
27731                    
27732                    $post['genderKey'] = $userData['callan_gender'];
27733                    $post['gender'] = isset($callanGender[$userData['callan_gender']]) ? $callanGender[$userData['callan_gender']] : ''; // change gender to human readable format
27734
27735                    $post['name'] = $userData['callan_first_name'];
27736                    $post['lastname'] = $userData['callan_last_name'];
27737                    $post['email'] = $userData['email'];
27738                    $post['userId'] = $userData['id'];
27739
27740                    // order info
27741                    $post['items'] = $cartItems;
27742                    $post['subtotal'] = $subTotal;
27743                    $post['total'] = $money;
27744
27745                    // add url
27746                    $post['url'] = myTools::getUrl() . '/admin/textbook_ebook-sales?id='.$textbook_sales_id;
27747
27748                    // set slack username
27749                    $post['slackUsername'] = "Ebook Purchase";
27750                    $post['invalid_email_flg'] = $userData['invalid_email_flg'];
27751
27752                    // set additional slack info (NJ-36233)
27753                    $post['currency_code'] = $userData['currency_code'];
27754                    $post['native_language'] = $userData['native_language2'];
27755
27756                    // send email
27757                    $sendEmailSlack = $this->sendEbookPurchaseEmailSlack($post, $userData);
27758
27759                } else if ($paymentStatusName ==  Configure::read('aftee.payment_status_error')) {
27760                    $afteeFailParams = array(
27761                        'ptId' => $pt['id'],
27762                        'afteeData' => array('aftee_directpayment_response' => $data),
27763                        'userId' => $userData['id'],
27764                        'money' => $money,
27765                        'formType' => $formType,
27766                        'priceId' => $userData['price_id'],
27767                        'paymentId' => $userData['payment_plan_id'],
27768                        'paymentType' => $paymentType,
27769                        'currency' => $userData['currency_code']
27770                    );
27771            
27772                    $this->log(__METHOD__ . ' aftee error --> ' . json_encode($data), $logFileName);
27773                    $this->Payment->afteeSaveFailedSettlement($afteeFailParams);
27774                    return array('error' => true, 'message' => 'aftee_create_order_error');
27775                }
27776                break;
27777            case Configure::read('payment_native_option_join'):
27778                $initialAmount = $amount;
27779                $sendId = isset($ptPaymentParams['sendId']) ? $ptPaymentParams['sendId'] : $userData['id'];
27780                $discounted_amount = isset($ptPaymentParams['discounted_amount']) ? $ptPaymentParams['discounted_amount'] : 0;
27781                $paymentType = Configure::read('payment_types.native_option');
27782                if ($paymentStatusName == Configure::read('aftee.payment_status_authorised')) {
27783                    $paymentData = array(
27784                        'user_id' => $userData['id'],
27785                        'amount' => $initialAmount,
27786                        'status' => 1,
27787                        'reference_id' => $sendId,
27788                        'payment_transaction_password' => $pt['password'],
27789                        'card_company' => $cardCompany,
27790                        'param1' => json_encode($data),
27791                        'form_type' => $formType,
27792                        'ordd' => $orderCode,
27793                        'transaction_code' => $orderCode,
27794                        'currency_id' => Configure::read('default.settlement_currency_id'), // set currency id to jpy
27795                        'currency_code' => $userData['currency_code'],
27796                        'price_id' => $userData['price_id'],
27797                        'payment_id' => $userData['payment_plan_id'],
27798                        'payment_type' => $paymentType,
27799                        'type_id' => 1,
27800                        'discounted_amount' => $discounted_amount
27801                    );
27802
27803                    // create new payment
27804                    $this->Payment->clear();
27805                    $this->Payment->create();
27806                    $this->Payment->set($paymentData);
27807                    $this->Payment->validate = array();
27808
27809                    // check if payment was not saved
27810                    if (!$this->Payment->save()) {
27811                        $this->log(__METHOD__ . ' Failed to save payment data. ' . json_encode($paymentData) . ' -- ' . json_encode($data), $logFileName);
27812                        $msg = 'Failed to save payment data';
27813                        throw new InternalErrorException($msg);
27814                    }
27815
27816                    // update native option to 1
27817                    $this->User->userNativeOptionProcess(array('user_id' => $userData['id'], 'type' => 'on'));
27818                    //NJ-2814 add logs
27819                    $optionLogParams = array(
27820                        'user_id' => $userData['id'],
27821                        'platform' => $ncTerminalType,
27822                        'status' => 1, // Join/Subscribed
27823                        'controller_name' => 'Payment',
27824                        'action_name' => 'handleAfteeDirectPaymentSuccess',
27825                        'user_type' => 0, // user
27826                        'option_before' => '',
27827                        'option_after' => 1,
27828                        'option_before_name' => '',
27829                        'option_after_name' => 'Native Unlimited Option',
27830                        'payment_plan_id' => $userData['payment_plan_id']
27831                    );
27832
27833                    ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
27834
27835                    // - save registration status step
27836                    $stepKey = Configure::read('registration_steps.user_info_entry');
27837                    $this->saveStep($userData['id'], $stepKey);
27838
27839                    //update/add user`s settlement amount
27840                    $this->User->updateUserPayments($paymentData);
27841
27842                    // update payment transaction
27843                    $updateData = array(
27844                        'id' => $pt['id'],
27845                        'fields' => array(
27846                            'status' => 1,
27847                            'response_text' => array('aftee_directPayment_response' => $data))
27848                    );
27849
27850                    // update payment transaction
27851                    if (!$this->PaymentTransaction->updateAfteePaymentTransaction($updateData)) {
27852                        $this->log(__METHOD__ . ' Failed to update payment transaction' . json_encode($updateData), $logFileName);
27853                        $msg = 'Failed to update payment transaction';
27854                        throw new InternalErrorException($msg);
27855                    }
27856                } else if ($paymentStatusName ==  Configure::read('aftee.payment_status_error')) {
27857                    // aftee payment params
27858                    $afteeParams = array(
27859                        'ptId' => $pt['id'],
27860                        'afteeData' => $data,
27861                        'userId' => $userData['id'],
27862                        'money' => $initialAmount,
27863                        'formType' => $formType,
27864                        'priceId' => $userData['price_id'],
27865                        'paymentId' => $userData['payment_plan_id'],
27866                        'paymentType' => $paymentType,
27867                        'currency' => $userData['currency_code']
27868                    );
27869                    $this->Payment->afteeSaveFailedSettlement($afteeParams);
27870                    $msg = 'Join Native Option Failed';
27871                    throw new InternalErrorException($msg);
27872                }
27873                break;
27874            case Configure::read('payment_callan_option_join'):
27875                $initialAmount = $amount;
27876                $sendId = isset($ptPaymentParams['sendId']) ? $ptPaymentParams['sendId'] : $userData['id'];
27877                $discounted_amount = isset($ptPaymentParams['discounted_amount']) ? $ptPaymentParams['discounted_amount'] : 0;
27878                $paymentType = Configure::read('payment_types.callan_option');
27879                if ($paymentStatusName == Configure::read('aftee.payment_status_authorised')) {
27880                    $paymentData = array(
27881                        'user_id' => $userData['id'],
27882                        'amount' => $initialAmount,
27883                        'status' => 1,
27884                        'reference_id' => $sendId,
27885                        'payment_transaction_password' => $pt['password'],
27886                        'card_company' => $cardCompany,
27887                        'param1' => json_encode($data),
27888                        'form_type' => $formType,
27889                        'ordd' => $orderCode,
27890                        'transaction_code' => $orderCode,
27891                        'currency_id' => Configure::read('default.settlement_currency_id'), // set currency id to jpy
27892                        'currency_code' => $userData['currency_code'],
27893                        'price_id' => $userData['price_id'],
27894                        'payment_id' => $userData['payment_plan_id'],
27895                        'payment_type' => $paymentType,
27896                        'type_id' => 1,
27897                        'discounted_amount' => $discounted_amount
27898                    );
27899
27900                    // create new payment
27901                    $this->Payment->clear();
27902                    $this->Payment->create();
27903                    $this->Payment->set($paymentData);
27904                    $this->Payment->validate = array();
27905
27906                    // check if payment was not saved
27907                    if (!$this->Payment->save()) {
27908                        $this->log(__METHOD__ . ' Failed to save payment data. ' . json_encode($paymentData) . ' -- ' . json_encode($data), $logFileName);
27909                        $msg = 'Failed to save payment data';
27910                        throw new InternalErrorException($msg);
27911                    }
27912
27913                    // update callan option to 1
27914                    $optionProcessData = array(
27915                        'user_id' => $userData['id'],
27916                        'type' => 'on',
27917                        'option_type' => Configure::read('callan_unlimited.options.callan_unlimited_option')
27918                    );
27919
27920                    $this->User->userNativeOptionProcess($optionProcessData);
27921
27922                    //NJ-2814 add logs
27923                    $optionLogParams = array(
27924                        'user_id' => $userData['id'],
27925                        'platform' => $ncTerminalType,
27926                        'status' => 1, // Join/Subscribed
27927                        'controller_name' => 'Payment',
27928                        'action_name' => 'handleAfteeDirectPaymentSuccess',
27929                        'user_type' => 0, // user
27930                        'option_before' => '',
27931                        'option_after' => 1,
27932                        'option_before_name' => '',
27933                        'option_after_name' => 'Callan Unlimited Option',
27934                        'option_type' => 2,
27935                        'payment_plan_id' => $userData['payment_plan_id']
27936                    );
27937
27938                    ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
27939
27940                    //update/add user`s settlement amount
27941                    $this->User->updateUserPayments($paymentData);
27942
27943                    // update payment transaction
27944                    $updateData = array(
27945                        'id' => $pt['id'],
27946                        'fields' => array(
27947                            'status' => 1,
27948                            'response_text' => array('aftee_directPayment_response' => $data))
27949                    );
27950
27951                    // update payment transaction
27952                    if (!$this->PaymentTransaction->updateAfteePaymentTransaction($updateData)) {
27953                        $this->log(__METHOD__ . ' Failed to update payment transaction' . json_encode($updateData), $logFileName);
27954                        $msg = 'Failed to update payment transaction';
27955                        throw new InternalErrorException($msg);
27956                    }
27957                } else if ($paymentStatusName ==  Configure::read('aftee.payment_status_error')) {
27958                    // aftee payment params
27959                    $afteeParams = array(
27960                        'ptId' => $pt['id'],
27961                        'afteeData' => $data,
27962                        'userId' => $userData['id'],
27963                        'money' => $initialAmount,
27964                        'formType' => $formType,
27965                        'priceId' => $userData['price_id'],
27966                        'paymentId' => $userData['payment_plan_id'],
27967                        'paymentType' => $paymentType,
27968                        'currency' => $userData['currency_code']
27969                    );
27970                    $this->Payment->afteeSaveFailedSettlement($afteeParams);
27971                    $msg = 'Join Callan Option Failed';
27972                    throw new InternalErrorException($msg);
27973                }
27974                break;
27975        }
27976        $response['success'] = true;
27977        return json_encode($response);
27978    }
27979
27980    // NC-7469 Nat Geo ebook send slack email after purchase
27981    public function sendNatGeoEbookPurchaseEmailSlack($data, $user){
27982        $url = myTools::getUrl() . '/admin/user-manage/member/'.$user['id'].'';
27983        $items = "・".implode("\n"."・", $data);
27984        $msg =  "<!subteam^S2PSWAG12|group-cs>" . "\n"; // mention
27985        $msg .= "```";
27986        $msg .= "\n種別: NATIONAL GEOGRAPHIC LEARNING eBook 購入";
27987        $msg .= "\nURL: ".$url."";
27988        $msg .= "\n\n購入内容: \n".$items."";
27989        $msg .= "\n会員ID: ".$user['id']."";
27990        $msg .= "\nニックネーム: ".$user['nickname']."";
27991        $msg .= "\nメールアドレス: ".$user['email']."";
27992        $msg .= "\n\nCS担当者は下記のシートを確認し、会員様にアクセスコードの付与をお願いします。";
27993        $msg .= "\nhttps://www.google.com/url?q=https://docs.google.com/spreadsheets/d/1aZ6ZadwlQcBqXgHjHjwqFMrYuttDWF4TYyyluXSR7_g/edit?usp%3Dsharing&sa=D&ust=1589170738599000&usg=AFQjCNFgZHdilvAmPYj4YnSjUu0v1hyrXA";
27994        $msg .= "```";
27995
27996        $mySlack = new mySlack();
27997        $mySlack->channel = myTools::checkChannel('#nc-nationalgeo-code','#fdc-test-channel');
27998        $mySlack->text = $msg;
27999        $mySlack->username = 'Ebook Purchase';
28000        $mySlack->sendSlack(); //Send slack
28001
28002    }
28003
28004    private function sendEbookPurchaseEmailSlack($data, $user) {
28005        // load Inquiry Model
28006        $this->loadModel("Inquiry");
28007
28008        // NC-7469 National Geo ebook
28009        $natGeoEbook = false;
28010        if ($data['totalNatGeoEbookItems'] > 0) {
28011            $natGeoEbook = true;
28012            $data['templateId'] = Configure::read('site_in_mail.student_purcahse_nat_geo_ebook_complete');
28013            $data['natGeoEbookUrl'] = myTools::getUrl() . '/text_description/national_geographic_ebook';
28014            $data['name'] = $user['nickname'];
28015            $this->sendNatGeoEbookPurchaseEmailSlack($data['items'], $user);
28016        }
28017
28018        // set param
28019        $param = array(
28020            'templateId' => $data['templateId'],
28021            'data' => $data
28022        );
28023
28024        $tempRes = $this->Inquiry->inqTemplate($param);
28025        $message = !empty($tempRes['text']) ? $tempRes['text'] : '';
28026
28027        // send email
28028        $sendMail = myMailer::sendHtmlOrPlainTextEMail(array(
28029            'email_to' => $data['email'],
28030            'email_subject' => !empty($tempRes['title']) ? $tempRes['title'] : '',
28031            'email_body_txt' => $message,
28032            'email_from' => !empty($tempRes['email_from']) ? $tempRes['email_from'] : '',
28033            'native_lang' => !empty($tempRes['native_lang']) ? $tempRes['native_lang'] : '',
28034            'invalid_email_flg' => isset($data['invalid_email_flg']) ? $data['invalid_email_flg'] : 0
28035        ), 'User');
28036
28037        if (!$natGeoEbook) {
28038            $suddenLesson = $this->User->getSuddenLessonCount($data['userId']);
28039            // prepare message
28040            $msg =  "<!subteam^S2PSWAG12|group-cs>" . "\n"; // mention
28041            $msg .= "```";
28042            $msg .= "\n種別:カランeBook購入申請";
28043            $msg .= "\nURL: %url%"; 
28044            $msg .= "\n\n購入内容:"; 
28045            $msg .= "\n%items%"; 
28046            $msg .= "\n\nName: %name%"; 
28047            $msg .= "\nSurname: %lname%";
28048            $msg .= "\nGender: %gender%"; 
28049            $msg .= "\nMember ID: <" . myTools::getUrl() . "/admin/user-manage/member/%userId%|%userId%>"; 
28050            $msg .= "\n通貨 : %currency_code%";
28051            $msg .= "\n言語 : %native_language%";
28052            $msg .= "\n直近30日の今すぐレッスン受講数: %sudden_lesson%回";
28053            $msg .= "```";
28054
28055            $valToReplace = array(
28056                "%url%",
28057                "%items%",
28058                "%name%",
28059                "%lname%",
28060                "%gender%",
28061                "%userId%",
28062                "%currency_code%",
28063                "%native_language%",
28064                "%sudden_lesson%"
28065            );
28066
28067            $replaceValues = array(
28068                isset($data['url']) ? $data['url'] : '',
28069                isset($data['items']) ? "・".implode("\n"."・", $data['items']) : '',
28070                isset($data['name']) ? $data['name'] : '',
28071                isset($data['lastname']) ? $data['lastname'] : '',
28072                isset($data['gender']) ? $data['gender'] : '',
28073                isset($data['userId']) ? $data['userId'] : '',
28074                isset($data['currency_code']) ? $data['currency_code'] : '',
28075                isset($data['native_language']) ? $data['native_language'] : '',
28076                isset($suddenLesson) ? $suddenLesson : '0'
28077            );
28078
28079            $msg = str_replace($valToReplace, $replaceValues ,$msg);
28080
28081            // send to slack
28082            // initialize myslack object
28083            $mySlack = new mySlack();
28084            $mySlack->channel = myTools::checkChannel('#nc-callan-order','#fdc-test-channel');
28085            $mySlack->text = $msg;
28086
28087            // set username
28088            if (!empty($data['slackUsername'])) {
28089                $mySlack->username = $data['slackUsername'];
28090            }
28091
28092            // send to slack
28093            $mySlack->sendSlack();
28094        }
28095
28096        // add memo to user
28097        $memoRes = $this->User->inquiryMemo(
28098            array(
28099                'userId' => $data['userId'],
28100                'data' => array(
28101                    'userId' => $data['userId'],
28102                    'memoTemplate' => $this->User->memoTemplateEbookPurchase,
28103                    'cart' => array(
28104                        'item' => $data['items']
28105                    )
28106                )
28107            )
28108        );
28109
28110        // check if there is error
28111        if (!empty($memoRes['error'])) {
28112        }
28113
28114        $returnVars['error']['is_error'] = false;
28115        return $returnVars; 
28116    }
28117
28118    private function isForTrialReenrollment($userId) {
28119        if ($userId) {    
28120            $reEnroll = $this->UsersDeactivationEnquate->find('first', array(
28121                'fields' => array('membership_type'),
28122                'conditions' => array(
28123                    'UsersDeactivationEnquate.user_id' => $userId,
28124                    'UsersDeactivationEnquate.membership_type' => Configure::read('student_status_type.card_auth')
28125                ),
28126                'order' => 'UsersDeactivationEnquate.created DESC'
28127            ));
28128    
28129            if (!empty($reEnroll)) {
28130                return true;
28131            }
28132        }
28133
28134        return false;
28135    }
28136
28137    /**
28138     * Zeus challenge response
28139     * Kickback from zeus 3d secure 2.0
28140     */
28141    public function checkZeusChallengeResponse(){
28142        $challengeResponse = $this->reportZeusChallengeResponse($this->request->data);
28143        $this->autoRender = $this->autoLayout = false;
28144        $response = $this->request->data;
28145        $response['zeusResponse'] = $challengeResponse;
28146        echo json_encode($response); die();
28147    }
28148
28149
28150    private function setPaymentPlanDetails($user = array(),$paymentPlanID = null ,$logFileName = null){
28151    
28152        if ($user && $paymentPlanID && $logFileName) {
28153                
28154            $currencyCode = $user['currency_code'];
28155            $userId = $user['id'];
28156            $indiCorpTypeLight = false;
28157            $cAmount = 0;
28158            
28159            if ($currencyCode == Configure::read('default.user_currency')) {
28160                // get premium payment plan data
28161                $ppData = $this->PaymentPlanPrice->getPaymentData(array(
28162                    'currencyCode' => $currencyCode,
28163                    'paymentPlanId' => $paymentPlanID,
28164                    'logFileName' => $logFileName
28165                ));
28166
28167                $corporateIndiUser = false;
28168                $corporateUser = isset($user['corporate_id']) && $user['corporate_id'] ? true : false;
28169                $corpType = myTools::getCoporateTypeUsingPaymentPlanId($user['payment_plan_id']);
28170
28171                // - set the default view
28172                $this->set('corporateIndiUser', $corporateIndiUser);
28173                $this->set('corporateType', $corpType);
28174                $this->set('currencyCode', $currencyCode);
28175                $this->set('indiCorpTypeLight', $indiCorpTypeLight);
28176
28177
28178                $cfAmount = "";
28179                $cpAmount = 0;
28180
28181                // if corporate user
28182                if ($corporateUser) {
28183                    // get corporate plan data
28184                    $cpData = $this->getCorporatePaymentPlan($user);
28185
28186                    // return to top page if not supported
28187                    if (!$cpData) {
28188                        return $this->redirect(myTools::getUrl() . '/');
28189                    }
28190
28191                    $cfAmount = $cpData['fAmount'];
28192                    $corporateIndiUser = $cpData['corporateIndiUser'];
28193
28194                }
28195
28196                //NJ-23812: - if corp indie user
28197                if ($corporateIndiUser) {
28198                    $corporateTaxRate = Configure::read('tax.increase');
28199                    
28200                    // light    
28201                    if ($corpType== Configure::read('corporate_type.light')) {
28202                        $indiCorpTypeLight = true;
28203                        $getCorporateData = $this->Corporate->getCorporateLightUserMonthly(array('user_id' => $userId, 'remove_heavy_flg' => true));
28204                        
28205                        $basicFeeWoTax = isset($getCorporateData['basic_fee_discounted']) ? $getCorporateData['basic_fee_discounted'] : 0;
28206                        $cAmount = $basicFeeWoTax;
28207                        $cfAmount = myTools::formatAmount($basicFeeWoTax);
28208
28209                    // standard or premium
28210                    }elseif (in_array($corpType, array(Configure::read('corporate_type.premium'), Configure::read('corporate_type.standard')))) {
28211                        $cdrParam = array('corporateId' => $user['corporate_id'], 'corporateType' => $corpType);
28212                        $discount = (int)$this->CorporateDiscountRate->getDiscount($cdrParam);
28213                        $cAmount = (int)$cpData['amount'] - $discount;
28214                        $cfAmount = myTools::formatAmount($cAmount);
28215                    }
28216                }
28217
28218                // NJ-23812 - set corp user indie
28219                $this->set('corporateIndiUser', $corporateIndiUser);//update 
28220                $this->set('corporateType',$corpType);
28221                $this->set('cpFormatAmount', $cfAmount);
28222                $this->set('cpAmount', $cAmount);
28223                $this->set('ppAmount', $ppData['amount']);
28224                $this->set('ppFormatAmount', $ppData['fAmount']);
28225
28226            }else{
28227
28228                // get premium payment plan data
28229                $ppData = $this->PaymentPlanPrice->getPaymentData(array(
28230                    'currencyCode' => $currencyCode,
28231                    'paymentPlanId' => $paymentPlanID,
28232                    'logFileName' => $logFileName
28233                ));
28234
28235                $currencyData = $this->Currency->getSymbolAndPosition($currencyCode);
28236
28237                $this->set('fAmount', $ppData['fAmount']);
28238                $this->set('ppAmount', $ppData['amount']);
28239
28240                $this->set('monthlyPrice', myTools::customFormatAmount($ppData['amount'], $currencyCode));
28241                $this->set('monthylyPriceNoTax', myTools::formatAmount($ppData['amountConstTaxDeducted']));
28242                $this->set('monthlyPriceSymbol',myTools::getCurrencySymbol($currencyCode));
28243
28244            }  // end if currency code
28245
28246        }
28247    }
28248
28249    private function corpIndividualData($user, $mobapp = array()) {
28250        $corporateIndiUser = false;
28251        $corporateUser = isset($user['corporate_id']) && $user['corporate_id'] ? true : false;
28252
28253        // if corporate user
28254        if ($corporateUser) {
28255            // get corporate plan data
28256            $cpData = $this->getCorporatePaymentPlan($user);
28257
28258            // return to top page if not supported
28259            if (!$cpData) {
28260                return $this->redirect(myTools::getUrl() . '/');
28261            }
28262
28263            $cfAmount = $cpData['fAmount'];
28264            $corporateIndiUser = $cpData['corporateIndiUser'];
28265
28266            $getActivePlans = $this->Corporate->find('first',
28267                [
28268                    'fields' => [
28269                        'cs_display_flg',
28270                        'cp_display_flg',
28271                        'clt_display_flg',
28272                    ],
28273                    'conditions' => [
28274                        'id' => $user['corporate_id']
28275                    ],
28276                    'recursive' => -1
28277                ]
28278            );
28279
28280            $getActivePlansCount = 0;
28281            $getActivePlansCount += $getActivePlans['Corporate']['cs_display_flg'] ? 1 : 0;
28282            $getActivePlansCount += $getActivePlans['Corporate']['cp_display_flg'] ? 1 : 0;
28283            $getActivePlansCount += $getActivePlans['Corporate']['clt_display_flg'] ? 1 : 0;
28284
28285            // default selected plans
28286            $defaultSelectedPlan = 'premium';
28287            if(isset($getActivePlans['Corporate']['cs_display_flg']) && $getActivePlans['Corporate']['cs_display_flg']) {
28288                $defaultSelectedPlan = 'standard';
28289            } else if(isset($getActivePlans['Corporate']['cp_display_flg']) && $getActivePlans['Corporate']['cp_display_flg']){
28290                $defaultSelectedPlan = 'premium';
28291            } else if(isset($getActivePlans['Corporate']['clt_display_flg']) && $getActivePlans['Corporate']['clt_display_flg']){
28292                $defaultSelectedPlan = 'light';
28293            }
28294
28295            $corpActivePlans = array(
28296                'standard'    => $getActivePlans['Corporate']['cs_display_flg'],
28297                'premium'    => $getActivePlans['Corporate']['cp_display_flg'],
28298                'light'        => $getActivePlans['Corporate']['clt_display_flg'],
28299                'count'        => $getActivePlansCount,
28300                'default_selected' => $defaultSelectedPlan
28301            );
28302            $this->set('corpActivePlans',$corpActivePlans);
28303        }
28304
28305        if ($corporateIndiUser) {
28306            $corporateTaxRate = Configure::read('tax.increase');
28307            $corporateIndiPrices = [];
28308
28309            //NJ-28462
28310            // Light Data Prices
28311            $getLightCorporateData = $this->Corporate->getCorporateLightUserMonthly(array(
28312                'user_id' => $user['id'],
28313                'remove_heavy_flg' => true
28314            ));
28315            $paymentLightAmount = isset($getLightCorporateData['total']) ? $getLightCorporateData['total'] : 0;
28316            $basicLightFee = isset($getLightCorporateData['basic_fee']) ? $getLightCorporateData['basic_fee'] : 0;
28317            $lessonLightFee = isset($getLightCorporateData['lesson_fee']) ? $getLightCorporateData['lesson_fee'] : 0;
28318            $basicLightFeeWoTax = isset($getLightCorporateData['basic_fee_discounted']) ? $getLightCorporateData['basic_fee_discounted'] : 0;
28319            $freeLightNumber = isset($getLightCorporateData['fee_charge_count']) ? $getLightCorporateData['fee_charge_count'] : 0;
28320            $isLightFreeFlg = isset($getLightCorporateData['free_charge_flg']) ? $getLightCorporateData['free_charge_flg'] : false;
28321            $monthlyLightFee = isset($getLightCorporateData['monthly_fee_wo_tax']) ? $getLightCorporateData['monthly_fee_wo_tax'] : 0;
28322            $cfLightAmount = myTools::formatAmount($basicLightFeeWoTax);
28323            $cLightRawAmount = $basicLightFeeWoTax;
28324            $lessonLightLimit = $this->Corporate->getLessonLimit($user['corporate_id']);
28325
28326            $CorpLightData = array(
28327                'basicFee' => $basicLightFee,
28328                'lessonFee' => $lessonLightFee,
28329                'freeFlg' => $isLightFreeFlg,
28330                'freeNumber' => $freeLightNumber,
28331                'monthlyFee' => $monthlyLightFee,
28332                'fAmount' => $cfLightAmount,
28333                'paymentAmount' => $paymentLightAmount,
28334                'lessonLimit' => $lessonLightLimit,
28335                'paymentPlanId' => $cpData['paymentPlanId'],
28336                'cRawAmount'    => $cLightRawAmount,
28337                'basicFeeWoTax' => $basicLightFeeWoTax,
28338            );
28339
28340            // Premium Data Prices
28341            $cpPremuimData = $this->getCorporatePaymentPlan($user,array('corporate_type' => 2));
28342            $cdrPremiumParam = array('corporateId' => $user['corporate_id'], 'corporateType' => 2);
28343            $discountPremium = (int)$this->CorporateDiscountRate->getDiscount($cdrPremiumParam);
28344            $cPremiumAmount = (int)$cpPremuimData['amount'] - $discountPremium;
28345            $cPremiumRawAmount = $cPremiumAmount;
28346            $cfPremiumAmount = myTools::formatAmount($cPremiumAmount);
28347            $corpPremiumData = array(
28348                'cprAmount' => $cpPremuimData['amount'],
28349                'cprDiscount' => $discountPremium,
28350                'paymentAmount' => $cPremiumAmount * $corporateTaxRate,
28351                'fAmount' => $cfPremiumAmount,
28352                'cRawAmount' => $cPremiumRawAmount,
28353                'ppAmount' => $cpPremuimData,
28354            );
28355
28356            // Standard Data Prices
28357            $cpStandardData = $this->getCorporatePaymentPlan($user,array('corporate_type' => 1));
28358            $cdrStandardParam = array('corporateId' => $user['corporate_id'], 'corporateType' => 1);
28359            $discountStandard = (int)$this->CorporateDiscountRate->getDiscount($cdrStandardParam);
28360            $cStandardAmount = (int)$cpStandardData['amount'] - $discountStandard;
28361            $cStandardRawAmount = $cStandardAmount;
28362            $cfStandardAmount = myTools::formatAmount($cStandardAmount);
28363            $corpStandardData = array(
28364                'cprAmount' => $cpStandardData['amount'],
28365                'cprDiscount' => $discountStandard,
28366                'paymentAmount' => $cStandardAmount * $corporateTaxRate,
28367                'fAmount' => $cfStandardAmount,
28368                'cRawAmount' => $cStandardRawAmount,
28369                'ppAmount' => $cpStandardData,
28370            );
28371
28372            $corporateIndiPrices['light'] = $CorpLightData;
28373            $corporateIndiPrices['premium'] = $corpPremiumData;
28374            $corporateIndiPrices['standard'] = $corpStandardData;
28375
28376            if(isset($corporateIndiPrices)) {
28377                $this->set('corporateIndiPrices', $corporateIndiPrices);
28378                if(count($mobapp) > 0) {
28379                    $this->memcache->set(array(
28380                        'key' => 'mobappcorporateIndiPrices_'.$mobapp['apiToken'],
28381                        'value' => $corporateIndiPrices,
28382                        'expire' => 3600
28383                    ));
28384                } else {
28385                    $this->Session->write('corporateIndiPrices', $corporateIndiPrices);
28386                }
28387
28388            }
28389
28390            if (isset($corpStandardData)) {
28391                if(count($mobapp) > 0) {
28392                    $this->memcache->set(array(
28393                        'key' => 'mobappCreditChargeCorporateData_'.$user['id'],
28394                        'value' => $corpStandardData,
28395                        'expire' => 3600
28396                    ));
28397                } else {
28398                    $this->Session->write('PaymentCreditChargeCorporateData', $corpStandardData);
28399                }
28400            }
28401        }
28402
28403    }
28404    
28405    /**
28406     * @api {get} /payment/corporate_change_individual_card_payment corporate_change_individual_card_payment()
28407     * @apiName corporate_change_individual_card_payment
28408     * @apiGroup Payment
28409     * @apiDescription This endpoint is used to display the corporate change individual card payment page.
28410     * 
28411     * @apiSuccess {View} Render Displays the corporate change individual card payment page.
28412     * 
28413     * @apiError {View} Redirect Redirects to {{ENV}}/ if the user is not logged in / not a corporate user.
28414     * 
28415     * @apiSuccessExample Success Response:
28416     * Renders the corporate change individual card payment page.
28417     * 
28418     * @apiErrorExample Error Response:
28419     * Redirects to {{ENV}}/
28420     * 
28421     * @apiSampleRequest off
28422     */
28423    public function corporate_change_individual_card_payment() {
28424        if(empty($this->sharedUserData['User'])){
28425            return $this->redirect('/');
28426        }
28427
28428        $userData = $this->sharedUserData['User'];
28429        $userObj = new UserTable($userData);
28430        $fromPage = $this->request->query('from_page');
28431        if (in_array($userObj->getMembershipTypeIndex(), Configure::read('common_corporate_payment_memberships'))) {
28432            return $this->redirect(myTools::getUrl() . '/common_corporate_payment?type='. Configure::read('payment_url_type.corporate_type.corporate_change_individual_card_payment') . '&from_page=' . $fromPage);
28433        }
28434
28435        if(!in_array($userObj->getMembershipTypeIndex(), Configure::read('corp_personal_card_payment_valid_memberships'))){
28436            return $this->redirect('/');
28437        }
28438
28439        $users_detail = $userObj->individualCardFailFlg();
28440        $this->set('individual_card_fail_flg', $users_detail['individual_card_fail_flg'] ?? 0);
28441
28442        $this->getAndSetCardInfo($userData);
28443        $this->set('zeusTransactionFlag', true);
28444        $this->setSupportPayPal($userData);
28445
28446        // - view
28447        $this->render('/Payment/corporate_change_individual_card_payment');
28448    }
28449
28450    public function corp_user_change_personal_card() {
28451        $this->autoRender = $this->autoLayout = false;
28452        $response = ['error' => true, 'msg' => 'Error occured'];
28453
28454        if ($this->request->is('post')) {
28455            $postData = $this->request->data;
28456            $userToken = isset($postData['userApiToken']) ? $postData['userApiToken'] : '';
28457
28458            $userData = [];
28459            if(!empty($this->sharedUserData['User'])){
28460                $userData = $this->sharedUserData['User'];
28461                $this->Session->write('corp_user_change_personal_card', 1);
28462            } elseif ($userToken) {
28463                $userData = $this->User->findByApiToken($userToken);
28464                $userData = $userData['User'];
28465            }
28466
28467            if(!$userData){
28468                $response['msg'] = 'Invalid user';
28469                return json_encode($response);
28470            }
28471
28472            $userObj = new UserTable($userData);
28473            if(!in_array($userObj->getMembershipTypeIndex(), Configure::read('corp_personal_card_payment_valid_memberships'))){
28474                $response['msg'] = 'User is not corporate';
28475                return json_encode($response);
28476            }
28477
28478            //- set user id
28479            $userId = $userObj->id;
28480
28481            //- NJ-42966 - check if user is already paying receivables combine with card registration
28482            $memcache_receivable_data = $this->memcache->get('memcache_receivable_data' . $userId);
28483            $isAleadyPaid = isset($memcache_receivable_data['paying_receivables']) && $memcache_receivable_data['paying_receivables'] == 1;
28484            $isPaymentFailed = isset($memcache_receivable_data['payment_status']) && $memcache_receivable_data['payment_status'] == 1;
28485
28486            // check if 3D secure are already executed
28487            if ($isAleadyPaid) {
28488                $response['error'] = false;
28489                $response['receivable_reservation'] = 1;
28490                $response['payment_status'] = $isPaymentFailed;
28491                $response['paying_receivables'] = $isAleadyPaid;
28492                $response['reserve_response'] = isset($memcache_receivable_data['add_reserve_response']) ? $memcache_receivable_data['add_reserve_response'] : null;
28493                $response['teacher_id'] = isset($memcache_receivable_data['request']['teacherId']) ? $memcache_receivable_data['request']['teacherId'] : 0;
28494                $response['msg'] = 'Already paid';
28495
28496                unset($memcache_receivable_data['paying_receivables']);
28497                unset($memcache_receivable_data['payment_status']);
28498
28499                $this->memcache->set(array(
28500                    'key' => 'memcache_receivable_data' . $userId,
28501                    'value' => $memcache_receivable_data,
28502                    'expire' => 1800 // 30 minutes
28503                ));
28504
28505                return json_encode($response);
28506            }
28507
28508            //- default amount
28509            $paymentAmount = 0;
28510
28511            // get receivable reservation payment
28512            $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userId);
28513            if ($receivablePayment) {
28514                $paymentAmount += $receivablePayment;
28515            }
28516
28517            // get appreciation receivable payments
28518            $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('appreciation_data.payment_element_type'));
28519            if ($appreciationReceivable) {
28520                $paymentAmount += $appreciationReceivable;
28521            }        
28522
28523            // get form information
28524            $data = $postData['ZPaymentFullLogs'];
28525
28526            // set payment params
28527            $paymentParams = array(
28528                'currencyCode' => $userData['currency_code'],
28529                'paymentPlanId' => $userData['payment_plan_id'],
28530                'priceId' => $userData['price_id'],
28531                'remoteAddress' => $_SERVER["REMOTE_ADDR"],
28532                'formType' => Configure::read('corporate_credit_card_registration'),
28533                'paymentType' => Configure::read('payment_types.payment_plan'),
28534                'paymentAmount' => $paymentAmount,
28535                'logFileName' => 'corporate_credit_card_registration',
28536                'corporateSettlementType' => Configure::read('corporate_settlement_types.corporate_card_registration')
28537            );
28538
28539            if (!empty($data['expyy']) && !empty($data['expmm'])) {
28540                $paymentParams['cardExpirationDate'] = date('Y-m-t', strtotime($data['expyy'] . '-' . $data['expmm']));
28541            }
28542
28543            $ptParams = array(
28544                'user_id' => $userId,
28545                'payment_hash' => myTools::generateOrderCode($userId),
28546                'payment_params' => json_encode($paymentParams),
28547                'course_id' => Configure::read("credit.course_id")
28548            );
28549
28550            // redirect to top page if failed to create payment transaction
28551            if (!$pt = $this->PaymentTransaction->setWPPaymentTransaction($ptParams)) {
28552                $response['msg'] = 'Error creating payment transaction';
28553                return json_encode($response);
28554            }
28555
28556            $zeuspayData = array(
28557                'clientIp' => Configure::read('ZEUS_clientip'), # clientip, # clientip
28558                'cardNumber' => isset($data['cardnumber']) ? (int) $data['cardnumber'] : null,
28559                'expyy' => isset($data['expyy']) ? (int) $data['expyy'] : null,
28560                'expmm' => isset($data['expmm']) ? (int) $data['expmm'] : null,
28561                'telNo' => Configure::read('credit.default_telno'), # telephone number
28562                'email' => $userData['email'], # email
28563                'username' => mb_strtoupper($data['username']), # username
28564                'sendId' => $userId, # id
28565                'money' => $paymentAmount, # money
28566                'tokenKey' => $data['zeusTokenValue'],
28567                'paymentHash' => $pt['payment_hash']
28568            );
28569
28570            require_once ROOT.'/user/Controller/Component/ZChargeComponent.php';
28571            // send curl request
28572            $paymentResponse = ZChargeComponent::charge_regist(json_encode($zeuspayData));
28573
28574            if (
28575                (!is_array($paymentResponse) && trim(strtolower($paymentResponse)) == 'success_order') || 
28576                (is_array($paymentResponse) && isset($paymentResponse[0]) && trim(strtolower($paymentResponse[0])) == 'success_order')
28577            ) {
28578
28579                $response['register_card'] = 1;
28580                $purchaseReservationData = '';
28581                $individual_payment_card_empty = false;
28582
28583                //NJ-20741
28584                $memcache_receivable_data = $this->memcache->get('memcache_receivable_data' . $userId);
28585                $reservationCoinPrice = isset($memcache_receivable_data['receivable_reservation_data']['reservation_coin_price']) ? $memcache_receivable_data['receivable_reservation_data']['reservation_coin_price'] : 0;
28586                if ((int)$reservationCoinPrice > 0) {
28587                    $response['teacher_id'] = isset($memcache_receivable_data['request']['teacherId']) ? $memcache_receivable_data['request']['teacherId'] : 0;
28588
28589                    if (isset($memcache_receivable_data['receivable_reservation_data']['reservation_coin_price'])) {
28590                        $memcache_receivable_data['paying_receivables'] = 1;
28591                        $response['receivable_reservation'] = 1;
28592
28593                        $reserveData = isset($memcache_receivable_data['reserve_data']) ? $memcache_receivable_data['reserve_data'] : null;
28594                        if (!empty($reserveData)) {
28595
28596                            $reserveData['paying_receivables'] = 1;
28597                            $reserveData['card_company'] = Configure::read('card_company.zeus');
28598                            if (isset($memcache_receivable_data['actionType']) && $memcache_receivable_data['actionType'] == 'lesson_reservation') {
28599                                try {
28600                                    $reserve_response = $this->LessonSchedule->addReserve($reserveData);
28601                                } catch (\Exception $e) {
28602                                    $this->LessonSchedule->sendSlackExceptionReport([
28603                                        'error_message' => $e->getMessage(),
28604                                        'reserve_data' => $reserveData
28605                                    ]);
28606                                }
28607                            } else if (isset($memcache_receivable_data['actionType']) && $memcache_receivable_data['actionType'] == 'reserved_confirmation') {
28608                                $reserve_response = $this->LessonSchedule->confirmReservationSchedule($reserveData);
28609                            }
28610
28611                            $memcache_receivable_data['reserve_response'] = $reserve_response;
28612
28613                            if (
28614                                isset($reserve_response['lessonSchedId']) && $reserve_response['lessonSchedId'] > 0 &&
28615                                isset($reserve_response['res']) && $reserve_response['res'] == 1
28616                            ) {
28617                                $memcache_receivable_data['add_reserve_response'] = 1;
28618                                $memcache_receivable_data['lessonSchedId'] = $reserve_response['lessonSchedId'];
28619                                $response['reserve_response'] = 1;
28620                            } else if (isset($reserve_response) && $reserve_response == '-1') {
28621                                $memcache_receivable_data['add_reserve_response'] = -1;
28622                                $response['reserve_response'] = -1;
28623                            }
28624
28625                            $individual_payment_card_empty = isset($memcache_receivable_data['receivable_reservation_data']['individual_payment_card_empty']) && $memcache_receivable_data['receivable_reservation_data']['individual_payment_card_empty'] == true;
28626                        }
28627                    }
28628
28629                    if (!empty($memcache_receivable_data)) {
28630                        $this->memcache->set([
28631                            'key' => 'memcache_receivable_data' . $userId,
28632                            'value' => $memcache_receivable_data, 
28633                            'expire' => 1800 // 30 minutes
28634                        ]);
28635                    }
28636                }
28637                // end NJ-20741
28638
28639                //- set success message
28640                $response['error'] = false;
28641                $response['msg'] = 'Successfully register card';
28642            } else {
28643                $response['msg'] = 'Failed to register card';
28644            }
28645
28646            if (!$response['error']) {
28647                $this->memcache->set(array(
28648                    'key' => 'register_or_charge_card_' . $userData['id'],
28649                    'value' => true,
28650                    'expire' => 3600 // 1 hour
28651                ));
28652            }
28653        }
28654
28655        return json_encode($response);
28656    }
28657    /**
28658     * @api {post} /payment/paypal_student_discount_user_change_card/:token paypal_student_discount_user_change_card()
28659     * @apiName paypal_student_discount_user_change_card
28660     * @apiGroup Payment
28661     * @apiDescription This endpoint is used to change the card of a student with a discount.
28662     * 
28663     * @apiParam {String} token User's API token.
28664     * @apiParam {Boolean} [negativeTesting] Negative testing flag.
28665     * 
28666     * @apiSuccess {Boolean} error Indicates if there was an error.
28667     * @apiSuccess {String} msg The message describing the result.
28668     * @apiSuccess {Number} [register_card] Indicates if the card was registered successfully.
28669     * @apiSuccess {Number} [teacher_id] The ID of the teacher.
28670     * @apiSuccess {Number} [receivable_reservation] Indicates if there is a receivable reservation.
28671     * @apiSuccess {Number} [reserve_response] The response for the reservation.
28672     * @apiSuccess {Number} [pay_receivables] Indicates if receivables were paid.
28673     * @apiSuccess {Number} [payment_status] The status of the payment.
28674     * 
28675     * @apiError {Boolean} error Indicates if there was an error.
28676     * @apiError {String} msg The message describing the result.
28677     * 
28678     * @apiSuccessExample Success Response:
28679     * {
28680     *   "error": false,
28681     *   "msg": "Successfully register card",
28682     *   "register_card": 1
28683     * }
28684     * 
28685     * @apiSuccessExample Success Response - Paying Receivables:
28686     * {
28687     *   "error": false,
28688     *   "msg": "Paying receivables",
28689     *   "pay_receivables": 1,
28690     *   "payment_status": 1
28691     * }
28692     * 
28693     * @apiErrorExample Error Response:
28694     * {
28695     *   "error": true,
28696     *   "msg": "Error occurred"
28697     * }
28698     * 
28699     * @apiErrorExample Error Response - Invalid User:
28700     * {
28701     *   "error": true,
28702     *   "msg": "Invalid user"
28703     * }
28704     * 
28705     * @apiErrorExample Error Response - Not Light Plan User:
28706     * {
28707     *   "error": true,
28708     *   "msg": "User is not light plan"
28709     * }
28710     * 
28711     * @apiErrorExample Error Response - Missing Billing Agreement Params:
28712     * {
28713     *   "error": true,
28714     *   "msg": "Missing billing agreement param(s)"
28715     * }
28716     * 
28717     * @apiErrorExample Error Response - Create Order Unsuccessful:
28718     * {
28719     *   "error": true,
28720     *   "msg": "Error creating payment transaction"
28721     * }
28722     * 
28723     * @apiErrorExample Error Response - Authorization Void Unsuccessful:
28724     * {
28725     *   "error": true,
28726     *   "msg": "Error occurred"
28727     * }
28728     * 
28729     * @apiErrorExample Error Response - Failed to Save Settlement History:
28730     * {
28731     *   "error": true,
28732     *   "msg": "Failed to save paypal data in settlement history"
28733     * }
28734     * 
28735     * @apiErrorExample Error Response - Failed to Save Payment Data:
28736     * {
28737     *   "error": true,
28738     *   "msg": "Failed to save payment data"
28739     * }
28740     * 
28741     * @apiErrorExample Error Response - Failed to Update User Data:
28742     * {
28743     *   "error": true,
28744     *   "msg": "Failed to update user data"
28745     * }
28746     * 
28747     * @apiErrorExample Error Response - Error Paying Receivables:
28748     * {
28749     *   "error": true,
28750     *   "msg": "Error Paying receivables"
28751     * }
28752     */
28753    public function paypal_student_discount_user_change_card() {
28754        $this->autoRender = $this->autoLayout = false;
28755        $logFileName = 'discount_option_debug';
28756        $response = ['error' => true, 'msg' => 'Error occured'];
28757        $get = $this->request->query;
28758
28759        // return error if token does is not set
28760        if (!isset($get['token'])) {
28761            $this->log(__METHOD__ . 'User api token does not exist. --> ' . json_encode($get), $logFileName);
28762            return json_encode($response);
28763        }
28764
28765        // negative testing
28766        if (isset($get['negativeTesting']) && $get['negativeTesting']) {
28767            return json_encode($response);
28768        }
28769
28770        if (!class_exists('myMemcached')) {
28771            App::uses('myMemcached', 'Lib');
28772        }
28773
28774        $userToken = $get['token'];
28775        $memcached = new myMemcached();
28776        $memKey = 'paypalBillingAgreementData_' . $userToken;
28777
28778        // return error if memcache billing agreement data does not exist
28779        if (!$paypalData = $memcached->get($memKey)) {
28780            $this->log(__METHOD__ . 'Memcached billing agreement data does not exist. --> ' . json_encode($paypalData) . ' | get data --> ' . json_encode($get), $logFileName);
28781            return json_encode($response);
28782        }
28783
28784        $userData = [];
28785        if (!empty($this->sharedUserData['User'])) {
28786            $userData = $this->sharedUserData['User'];
28787        } elseif ($userToken) {
28788            $userData = $this->User->findByApiToken($userToken);
28789            $userData = $userData['User'];
28790        }
28791
28792        // return error if user does not exist
28793        if (!$userData) {
28794            $response['msg'] = 'Invalid user';
28795            return json_encode($response);
28796        }
28797
28798        $userObj = new UserTable($userData);
28799
28800        // return error if not light plan user
28801        if (!in_array($userObj->getMembershipTypeIndex(), Configure::read('membership_type_lightplan'))){
28802            $response['msg'] = 'User is not light plan';
28803            return json_encode($response);
28804        }
28805
28806        // set payment params
28807        $paymentParams = array(
28808            'currencyCode' => $userData['currency_code'],
28809            'paymentPlanId' => $userData['payment_plan_id'],
28810            'priceId' => $userData['price_id'],
28811            'remoteAddress' => $_SERVER["REMOTE_ADDR"],
28812            'formType' => Configure::read('payment_credit_change'),
28813            'paymentType' => Configure::read('payment_types.payment_plan'),
28814            'paymentAmount' => 0,
28815            'logFileName' => $logFileName
28816        );
28817
28818        // initialize variables
28819        $userId = $userObj->id;
28820        $currencyCode = $userObj->currency_code;
28821        $paymentPlanId = $userObj->payment_plan_id;
28822        $priceId = $userObj->price_id;
28823        $paymentHash = myTools::generateOrderCode($userId);
28824        $ptParams = array(
28825            'user_id' => $userId,
28826            'payment_hash' => $paymentHash,
28827            'payment_params' => json_encode($paymentParams),
28828            'course_id' => Configure::read("credit.course_id")
28829        );
28830
28831        // return error if failed to create payment transaction
28832        if (!$pt = $this->PaymentTransaction->setWPPaymentTransaction($ptParams)) {
28833            $response['msg'] = 'Error creating payment transaction';
28834            return json_encode($response);
28835        }
28836
28837        $ptId = $pt['id'];
28838
28839        // return error if missing billing agreement params
28840        if (
28841            !isset($paypalData['accessTokenData']['access_token']) || 
28842            !isset($paypalData['finalizeBillingAgreementData']['id']) ||
28843            !isset($paypalData['finalizeBillingAgreementData']['payer']['payer_info']['payer_id'])
28844        ) {
28845            $this->log(__METHOD__ . 'Missing billing agreement param(s). --> ' . json_encode($paypalData), $logFileName);
28846
28847            // update payment transaction
28848            $this->PaymentTransaction->paypalUpdatePaymentTransaction(array('ptId' => $ptId, 'paypalData' => $paypalData));
28849
28850            return json_encode($response);
28851        }
28852
28853        $accessToken = $paypalData['accessTokenData']['access_token'];
28854        $baId = $paypalData['finalizeBillingAgreementData']['id']; // billing agreement id
28855        $payerId = $paypalData['finalizeBillingAgreementData']['payer']['payer_info']['payer_id'];
28856
28857        // load PayPal class
28858        if (!class_exists('PayPal')) {
28859            App::import('Lib', 'PayPal');
28860        }
28861
28862        $paypal = new PayPal();
28863        $createOrderParams = array(
28864            'accessToken' => $accessToken,
28865            'paypalRequestId' => $ptId,
28866            'intent' => 'AUTHORIZE',
28867            'paymentHash' => $paymentHash,
28868            'userId' => $userId,
28869            'currencyCode' => $currencyCode,
28870            'amount' => 1,
28871            'billingAgreementId' => $baId
28872        );
28873
28874        // create order
28875        $orderResult = $paypal->createOrder($createOrderParams);
28876
28877        $paypalData['create_order_data'] = $orderResult;
28878
28879        // return error if create order unsuccessful
28880        if (!isset($orderResult['status']) || (isset($orderResult['status']) && $orderResult['status'] !== 'COMPLETED')) {
28881            $this->log(__METHOD__ . 'Create order error. --> ' . json_encode($orderResult) . ' | params --> ' . json_encode($createOrderParams) . ' | paypal data --> ' . json_encode($paypalData), $logFileName);
28882
28883            // update payment transaction
28884            $this->PaymentTransaction->paypalUpdatePaymentTransaction(array('ptId' => $ptId, 'paypalData' => $paypalData));
28885
28886            return json_encode($response);
28887        }
28888
28889        $authorizationVoidParams = array(
28890            'accessToken' => $accessToken,
28891            'authorizationId' => $orderResult['purchase_units'][0]['payments']['authorizations'][0]['id']
28892        );
28893
28894        // void authorization
28895        // expected return empty if success
28896        $voidResult = $paypal->authorizationVoid($authorizationVoidParams);
28897
28898        $paypalData['authorization_void_data'] = $voidResult; // expected empty
28899
28900        // return error if paypal transaction unsuccessful
28901        if (!empty($voidResult)) {
28902            $this->log(__METHOD__ . ' authorization void error. --> ' . json_encode($voidResult) . ' | params --> ' . json_encode($authorizationVoidParams) . ' | paypal data --> ' . json_encode($paypalData), $logFileName);
28903
28904            // update payment transaction
28905            $this->PaymentTransaction->paypalUpdatePaymentTransaction(array('ptId' => $ptId, 'paypalData' => $paypalData));
28906
28907            return json_encode($response);
28908        }
28909
28910        // save settlement history for tracking
28911        if (!SettlementHistoryTable::add(
28912            array(
28913                'userId' => $userId,
28914                'params' => json_encode($paypalData)
28915            )
28916        )) {
28917            $this->log(__METHOD__ . 'Failed to save paypal data in settlement history. --> ' . json_encode($orderResult) . ' | params --> ' . json_encode($createOrderParams) . ' | paypal data --> ' . json_encode($paypalData), $logFileName);
28918
28919            // update payment transaction
28920            $this->PaymentTransaction->paypalUpdatePaymentTransaction(array('ptId' => $ptId, 'paypalData' => $paypalData));
28921
28922            return json_encode($response);
28923        }
28924
28925        $cardCompany = Configure::read('card_company.paypal');
28926
28927        $savePaymentArr = array(
28928            'user_id' => $userId,
28929            'amount' => 0,
28930            'status' => 1,
28931            'reference_id' => $userId,
28932            'payment_transaction_password' => $pt['password'],
28933            'card_company' => $cardCompany,
28934            'param1' => "paypal change card, payment transaction id: {$ptId}",
28935            'form_type' => Configure::read('payment_credit_change'),
28936            'ordd' => $paymentHash,
28937            'transaction_code' => $paymentHash,
28938            'currency_id' => Configure::read('default.settlement_currency_id'), // set currency id to jpy
28939            'currency_code' => $currencyCode,
28940            'payment_id' => $paymentPlanId,
28941            'price_id' => $priceId,
28942            'payment_type' => Configure::read('payment_types.payment_plan')
28943        );
28944
28945        // create new payment
28946        $this->Payment->clear();
28947        $this->Payment->create();
28948        $this->Payment->set($savePaymentArr);
28949        if (!$this->Payment->save()) {
28950            $this->log(__METHOD__ . ' Failed to save payment data. --> ' . json_encode($savePaymentArr) . ' | paypal data --> ' . json_encode($paypalData), $logFileName);
28951            $dataSource->rollback();
28952
28953            // update payment transaction
28954            $this->PaymentTransaction->paypalUpdatePaymentTransaction(array('ptId' => $ptId, 'paypalData' => $paypalData));
28955
28956            return json_encode($response);
28957        }
28958
28959        $dateNow = date('Y-m-d H:i:s');
28960        $saveUserArr = array(
28961            'status' => 1,
28962            'modified' => $dateNow,
28963            'fail_flg' => 0,
28964            'charge_flg' => 1,
28965            'counseling_attended_flg' => 0,
28966            'card_company' => $cardCompany,
28967            'hash16' => $userId,
28968            'last_charge_date' => $dateNow,
28969            'paypal_billing_agreement_id' => $baId,
28970            'paypal_payer_id' => $payerId,
28971            'card_expiration_date' => null
28972        );
28973
28974        $this->User->read(array_keys($saveUserArr), $userId);
28975        $this->User->set($saveUserArr);
28976        $this->User->validate = array();
28977        if (!$this->User->save()) {
28978            $this->log(__METHOD__ . ' Failed to update user data. --> ' . json_encode($saveUserArr) . ' | user id --> ' . $userId . ' | paypal data --> ' . json_encode($paypalData), $logFileName);
28979            return json_encode($response);
28980        }
28981
28982        $response['register_card'] = 1;
28983        $purchaseReservationData = '';
28984        $individual_payment_card_empty = false;
28985        $memcache_receivable_data = $this->memcache->get('memcache_receivable_data' . $userId);
28986        $reservationCoinPrice = isset($memcache_receivable_data['receivable_reservation_data']['reservation_coin_price']) ? $memcache_receivable_data['receivable_reservation_data']['reservation_coin_price'] : 0;
28987        if ((int)$reservationCoinPrice > 0) {
28988            $response['teacher_id'] = isset($memcache_receivable_data['request']['teacherId']) ? $memcache_receivable_data['request']['teacherId'] : 0;
28989
28990            if (isset($memcache_receivable_data['receivable_reservation_data']['reservation_coin_price'])) {
28991                $memcache_receivable_data['paying_receivables'] = 1;
28992                $response['receivable_reservation'] = 1;
28993
28994                $reserveData = isset($memcache_receivable_data['reserve_data']) ? $memcache_receivable_data['reserve_data'] : null;
28995                if (!empty($reserveData)) {
28996
28997                    $reserveData['paying_receivables'] = 1;
28998                    $reserveData['card_company'] = Configure::read('card_company.zeus');
28999                    if (isset($memcache_receivable_data['actionType']) && $memcache_receivable_data['actionType'] == 'lesson_reservation') {
29000                        try {
29001                            $reserve_response = $this->LessonSchedule->addReserve($reserveData);
29002                        } catch (\Exception $e) {
29003                            $this->LessonSchedule->sendSlackExceptionReport([
29004                                'error_message' => $e->getMessage(),
29005                                'reserve_data' => $reserveData
29006                            ]);
29007                        }
29008                    } else if (isset($memcache_receivable_data['actionType']) && $memcache_receivable_data['actionType'] == 'reserved_confirmation') {
29009                        $reserve_response = $this->LessonSchedule->confirmReservationSchedule($reserveData);
29010                    }
29011
29012                    $memcache_receivable_data['reserve_response'] = $reserve_response;
29013
29014                    if (
29015                        isset($reserve_response['lessonSchedId']) && $reserve_response['lessonSchedId'] > 0 &&
29016                        isset($reserve_response['res']) && $reserve_response['res'] == 1
29017                    ) {
29018                        $memcache_receivable_data['add_reserve_response'] = 1;
29019                        $memcache_receivable_data['lessonSchedId'] = $reserve_response['lessonSchedId'];
29020                        $response['reserve_response'] = 1;
29021                    } else if (isset($reserve_response) && $reserve_response == '-1') {
29022                        $memcache_receivable_data['add_reserve_response'] = -1;
29023                        $response['reserve_response'] = -1;
29024                    }
29025
29026                    $individual_payment_card_empty = isset($memcache_receivable_data['receivable_reservation_data']['individual_payment_card_empty']) && $memcache_receivable_data['receivable_reservation_data']['individual_payment_card_empty'] == true;
29027                }
29028            }
29029
29030            if (!empty($memcache_receivable_data)) {
29031                $this->memcache->set([
29032                    'key' => 'memcache_receivable_data' . $userId,
29033                    'value' => $memcache_receivable_data, 
29034                    'expire' => 1800 // 30 minutes
29035                ]);
29036            }
29037        }
29038
29039        $paymentAmount = 0;
29040
29041        // get receivable reservation payment
29042        $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userId);
29043        if ($receivablePayment) {
29044            $paymentAmount += $receivablePayment;
29045        }
29046
29047        // - pay receivables
29048        if ($paymentAmount && $individual_payment_card_empty == false) {
29049            $response['pay_receivables'] = 1;
29050
29051            // - payment transaction params
29052            $paymentHash = myTools::generateOrderCode($userId);
29053            $receivablePT = array(
29054                'userId' => $userId,
29055                'status' => 0,
29056                'paymentHash' => $paymentHash,
29057                'paymentParams' => json_encode(array(
29058                    'currencyCode' => $currencyCode,
29059                    'formType' => Configure::read('payment_credit_receivable'),
29060                    'paymentType' => Configure::read('payment_types.payment_receivable'),
29061                    'paymentAmount' => $paymentAmount,
29062                    'paymentPlanId' => $paymentPlanId,
29063                    'priceId' => $priceId
29064                )),
29065                'responseText' => '',
29066                'logFileName' => ''
29067            );
29068
29069            if (!$pt = $this->PaymentTransaction->setWPPaymentTransaction($ptParams)) {
29070                $response['error'] = true;
29071                $response['msg'] = 'Error creating payment trasaction for receivable payments';
29072                return json_encode($response);
29073            }
29074
29075            $ptId = $pt['id'];
29076
29077            // settle receivable
29078            $createOrderParams = array(
29079                'accessToken' => $accessToken,
29080                'paypalRequestId' => $ptId,
29081                'intent' => 'CAPTURE',
29082                'paymentHash' => $paymentHash,
29083                'userId' => $userId,
29084                'currencyCode' => $currencyCode,
29085                'amount' => (int)$paymentAmount,
29086                'billingAgreementId' => $baId
29087            );
29088
29089            // create order
29090            $createOrderResult = $paypal->createOrder($createOrderParams);
29091            $paypalData['create_order_data'] = $createOrderResult;
29092
29093            // save settlement history for tracking
29094            if (
29095                !SettlementHistoryTable::add(array(
29096                    'userId' => $userId,
29097                    'params' => json_encode($paypalData),
29098                    'createdIp' => $dateNow,
29099                    'modifiedIp' => $dateNow
29100                )
29101            )) {
29102                $this->log(__METHOD__ . ' Failed to save paypal result data in settlement history. ' . json_encode($paypalData), $logFileName);
29103                return json_encode($response);
29104            }
29105
29106            if (isset($createOrderResult['status']) && $createOrderResult['status'] === 'COMPLETED') {
29107                $paymentData = array(
29108                    'user_id' => $userId,
29109                    'amount' => $paymentAmount,
29110                    'status' => 1,
29111                    'reference_id' => $userId,
29112                    'payment_transaction_password' => $pt['password'],
29113                    'card_company' => $cardCompany,
29114                    'param1' => json_encode($paypalData),
29115                    'form_type' => Configure::read('payment_credit_receivable'),
29116                    'ordd' => $paymentHash,
29117                    'transaction_code' => $paymentHash,
29118                    'currency_id' => Configure::read('default.settlement_currency_id'),
29119                    'currency_code' => $currencyCode,
29120                    'payment_id' => $paymentPlanId,
29121                    'price_id' => $priceId,
29122                    'payment_type' => Configure::read('payment_types.payment_plan')
29123                );
29124    
29125                // create new payment
29126                $this->Payment->clear();
29127                $this->Payment->create();
29128                $this->Payment->set($paymentData);
29129                $this->Payment->validate = array();
29130    
29131                // check if payment was not saved
29132                if (!$this->Payment->save()) {
29133                    $this->log(__METHOD__ . ' Failed to save payment data. ' . json_encode($paymentData) . ' -- ' . json_encode($data), $logFileName);
29134                    return json_encode($response);
29135                }
29136    
29137                $paymentId = $this->Payment->id;
29138                //update/add user`s settlement amount
29139                $this->User->updateUserPayments($paymentData);
29140
29141                // set payment_id
29142                $paymentId = $this->Payment->id;
29143                $membershipStatusIndex = UserTable::getStudentMembershipStatus($userId);
29144
29145                // set payment receivable statuses to 2 - received
29146                $this->PaymentReceivable->updateReceivableReservationPayment(
29147                    $userId,
29148                    array(
29149                        'status' => 2,
29150                        'payment_id' => $paymentId,
29151                        'payment_collection_date' => date("Y-m-d H:i:s"),
29152                        'card_company' => $cardCompany,
29153                        'payment_plan_id' => $paymentPlanId,
29154                        'membership_type_index' => $membershipStatusIndex
29155                    ),
29156                    array(
29157                        'PaymentReceivable.user_id' => $userId,
29158                        'PaymentReceivable.status' => 0,
29159                        'PaymentReceivable.payment_element_type' => 1,
29160                        'PaymentReceivable.created <=' => date("Y-m-d H:i:s")
29161                    )
29162                );
29163
29164                $response['payment_status'] = 1;
29165                $response['error'] = false;
29166                $response['msg'] = 'Paying receivables';
29167            } else {
29168                $response['msg'] = 'Error Paying receivables';
29169            }
29170        } else {
29171            $response['error'] = false;
29172            $response['msg'] = 'Successfully register card';
29173        }
29174
29175        if (!$response['error']) {
29176            $this->memcache->set(array(
29177                'key' => 'register_or_charge_card_' . $userData['id'],
29178                'value' => true,
29179                'expire' => 3600 // 1 hour
29180            ));
29181        }
29182
29183        return json_encode($response);
29184    }
29185    /**
29186     * @api {post} /payment/student_discount_user_change_card/:token student_discount_user_change_card()
29187     * @apiName student_discount_user_change_card
29188     * @apiGroup Payment
29189     * @apiDescription This endpoint is used to change the card of a student with a discount.
29190     * 
29191     * @apiParam {String} token User's API token.
29192     * @apiParam {Boolean} [negativeTesting] Negative testing flag.
29193     * 
29194     * @apiSuccess {Boolean} error Indicates if there was an error.
29195     * @apiSuccess {String} msg The message describing the result.
29196     * @apiSuccess {Number} [register_card] Indicates if the card was registered successfully.
29197     * @apiSuccess {Number} [teacher_id] The ID of the teacher.
29198     * @apiSuccess {Number} [receivable_reservation] Indicates if there is a receivable reservation.
29199     * @apiSuccess {Number} [reserve_response] The response for the reservation.
29200     * @apiSuccess {Number} [pay_receivables] Indicates if receivables were paid.
29201     * @apiSuccess {Number} [payment_status] The status of the payment.
29202     * 
29203     * @apiError {Boolean} error Indicates if there was an error.
29204     * @apiError {String} msg The message describing the result.
29205     * 
29206     * @apiSuccessExample Success Response:
29207     * {
29208     *   "error": false,
29209     *   "msg": "Successfully register card",
29210     *   "register_card": 1
29211     * }
29212     * 
29213     * @apiSuccessExample Success Response - Paying Receivables:
29214     * {
29215     *   "error": false,
29216     *   "msg": "Paying receivables",
29217     *   "pay_receivables": 1,
29218     *   "payment_status": 1
29219     * }
29220     * 
29221     * @apiErrorExample Error Response:
29222     * {
29223     *   "error": true,
29224     *   "msg": "Error occurred"
29225     * }
29226     * 
29227     * @apiErrorExample Error Response - Invalid User:
29228     * {
29229     *   "error": true,
29230     *   "msg": "Invalid user"
29231     * }
29232     * 
29233     * @apiErrorExample Error Response - Not Light Plan User:
29234     * {
29235     *   "error": true,
29236     *   "msg": "User is not light plan"
29237     * }
29238     * 
29239     * @apiErrorExample Error Response - Failed to Register Card:
29240     * {
29241     *   "error": true,
29242     *   "msg": "Failed to register card"
29243     * }
29244     * 
29245     * @apiErrorExample Error Response - Error Creating Payment Transaction:
29246     * {
29247     *   "error": true,
29248     *   "msg": "Error creating payment transaction"
29249     * }
29250     *     
29251     * @apiErrorExample Error Response - Error Paying Receivables:
29252     * {
29253     *   "error": true,
29254     *   "msg": "Error Paying receivables"
29255     * }
29256     */
29257    public function student_discount_user_change_card() {
29258        $this->autoRender = $this->autoLayout = false;
29259        $response = ['error' => true, 'msg' => 'Error occured'];
29260
29261        if ($this->request->is('post')) {
29262            $postData = $this->request->data;
29263            $userToken = isset($postData['userApiToken']) ? $postData['userApiToken'] : '';
29264
29265            $userData = [];
29266            if (!empty($this->sharedUserData['User'])) {
29267                $userData = $this->sharedUserData['User'];
29268            } elseif ($userToken) {
29269                $userData = $this->User->findByApiToken($userToken);
29270                $userData = $userData['User'];
29271            }
29272
29273            if (!$userData) {
29274                $response['msg'] = 'Invalid user';
29275                return json_encode($response);
29276            }
29277
29278            $userObj = new UserTable($userData);
29279            if (!in_array($userObj->getMembershipTypeIndex(), Configure::read('membership_type_lightplan'))){
29280                $response['msg'] = 'User is not light plan';
29281                return json_encode($response);
29282            }
29283
29284            // get form information
29285            $data = $postData['ZPaymentFullLogs'];
29286
29287            // set payment params
29288            $paymentParams = array(
29289                'currencyCode' => $userData['currency_code'],
29290                'paymentPlanId' => $userData['payment_plan_id'],
29291                'priceId' => $userData['price_id'],
29292                'remoteAddress' => $_SERVER["REMOTE_ADDR"],
29293                'formType' => Configure::read('payment_credit_change'),
29294                'paymentType' => Configure::read('payment_types.payment_plan'),
29295                'paymentAmount' => 0,
29296                'logFileName' => 'discount_option_debug'
29297            );
29298
29299            if (!empty($data['expyy']) && !empty($data['expmm'])) {
29300                $paymentParams['cardExpirationDate'] = date('Y-m-t', strtotime($data['expyy'] . '-' . $data['expmm']));
29301            }
29302
29303            $userId = $userData['id'];
29304            $ptParams = array(
29305                'user_id' => $userId,
29306                'payment_hash' => myTools::generateOrderCode($userId),
29307                'payment_params' => json_encode($paymentParams),
29308                'course_id' => Configure::read("credit.course_id")
29309            );
29310
29311            // redirect to top page if failed to create payment transaction
29312            if (!$pt = $this->PaymentTransaction->setWPPaymentTransaction($ptParams)) {
29313                $response['msg'] = 'Error creating payment transaction';
29314                return json_encode($response);
29315            }
29316
29317            $zeuspayData = array(
29318                'clientIp' => Configure::read('ZEUS_clientip'), # clientip, # clientip
29319                'cardNumber' => isset($data['cardnumber']) ? (int) $data['cardnumber'] : null,
29320                'expyy' => isset($data['expyy']) ? (int) $data['expyy'] : null,
29321                'expmm' => isset($data['expmm']) ? (int) $data['expmm'] : null,
29322                'telNo' => Configure::read('credit.default_telno'), # telephone number
29323                'email' => $userData['email'], # email
29324                'username' => mb_strtoupper($data['username']), # username
29325                'sendId' => $userId, # id
29326                'money' => 0, # money
29327                'tokenKey' => $data['zeusTokenValue'],
29328                'paymentHash' => $pt['payment_hash']
29329            );
29330
29331            //NJ-20741
29332            $memcache_receivable_data = $this->memcache->get('memcache_receivable_data' . $userId);
29333            $isAleadyPaid = isset($memcache_receivable_data['paying_receivables']) && $memcache_receivable_data['paying_receivables'] == 1;
29334            $isPaymentFailed = isset($memcache_receivable_data['payment_status']) && $memcache_receivable_data['payment_status'] == 1;
29335            
29336            // check if 3D secure are already executed
29337            if ($isAleadyPaid) {
29338                $response['error'] = false;
29339                $response['receivable_reservation'] = 1;
29340                $response['payment_status'] = $isPaymentFailed;
29341                $response['paying_receivables'] = $isAleadyPaid;
29342                $response['reserve_response'] = isset($memcache_receivable_data['add_reserve_response']) ? $memcache_receivable_data['add_reserve_response'] : null;
29343                $response['teacher_id'] = isset($memcache_receivable_data['request']['teacherId']) ? $memcache_receivable_data['request']['teacherId'] : 0;
29344                $response['msg'] = 'Already paid';
29345
29346                unset($memcache_receivable_data['paying_receivables']);
29347                unset($memcache_receivable_data['payment_status']);
29348
29349                $this->memcache->set(array(
29350                    'key' => 'memcache_receivable_data' . $userId,
29351                    'value' => $memcache_receivable_data,
29352                    'expire' => 1800 // 30 minutes
29353                ));
29354
29355                return json_encode($response);
29356            }
29357
29358            require_once ROOT.'/user/Controller/Component/ZChargeComponent.php';
29359            // send curl request
29360            $paymentResponse = ZChargeComponent::charge_regist(json_encode($zeuspayData));
29361
29362            if (
29363                (!is_array($paymentResponse) && trim(strtolower($paymentResponse)) == 'success_order') || 
29364                (is_array($paymentResponse) && isset($paymentResponse[0]) && trim(strtolower($paymentResponse[0])) == 'success_order')
29365            ) {
29366
29367                $response['register_card'] = 1;
29368                $purchaseReservationData = '';
29369                $individual_payment_card_empty = false;
29370
29371                //NJ-20741
29372                $memcache_receivable_data = $this->memcache->get('memcache_receivable_data' . $userId);
29373                $reservationCoinPrice = isset($memcache_receivable_data['receivable_reservation_data']['reservation_coin_price']) ? $memcache_receivable_data['receivable_reservation_data']['reservation_coin_price'] : 0;
29374                if ((int)$reservationCoinPrice > 0) {
29375                    $response['teacher_id'] = isset($memcache_receivable_data['request']['teacherId']) ? $memcache_receivable_data['request']['teacherId'] : 0;
29376
29377                    if (isset($memcache_receivable_data['receivable_reservation_data']['reservation_coin_price'])) {
29378                        $memcache_receivable_data['paying_receivables'] = 1;
29379                        $response['receivable_reservation'] = 1;
29380
29381                        $reserveData = isset($memcache_receivable_data['reserve_data']) ? $memcache_receivable_data['reserve_data'] : null;
29382                        if (!empty($reserveData)) {
29383
29384                            $reserveData['paying_receivables'] = 1;
29385                            $reserveData['card_company'] = Configure::read('card_company.zeus');
29386                            if (isset($memcache_receivable_data['actionType']) && $memcache_receivable_data['actionType'] == 'lesson_reservation') {
29387                                try {
29388                                    $reserve_response = $this->LessonSchedule->addReserve($reserveData);
29389                                } catch (\Exception $e) {
29390                                    $this->LessonSchedule->sendSlackExceptionReport([
29391                                        'error_message' => $e->getMessage(),
29392                                        'reserve_data' => $reserveData
29393                                    ]);
29394                                }
29395                            } else if (isset($memcache_receivable_data['actionType']) && $memcache_receivable_data['actionType'] == 'reserved_confirmation') {
29396                                $reserve_response = $this->LessonSchedule->confirmReservationSchedule($reserveData);
29397                            }
29398
29399                            $memcache_receivable_data['reserve_response'] = $reserve_response;
29400
29401                            if (
29402                                isset($reserve_response['lessonSchedId']) && $reserve_response['lessonSchedId'] > 0 &&
29403                                isset($reserve_response['res']) && $reserve_response['res'] == 1
29404                            ) {
29405                                $memcache_receivable_data['add_reserve_response'] = 1;
29406                                $memcache_receivable_data['lessonSchedId'] = $reserve_response['lessonSchedId'];
29407                                $response['reserve_response'] = 1;
29408                            } else {
29409                                $memcache_receivable_data['add_reserve_response'] = -1;
29410                                $response['reserve_response'] = -1;
29411                            }
29412
29413                            $individual_payment_card_empty = isset($memcache_receivable_data['receivable_reservation_data']['individual_payment_card_empty']) && $memcache_receivable_data['receivable_reservation_data']['individual_payment_card_empty'] == true;
29414                        }
29415                    }
29416
29417                    if (!empty($memcache_receivable_data)) {
29418                        $this->memcache->set([
29419                            'key' => 'memcache_receivable_data' . $userId,
29420                            'value' => $memcache_receivable_data, 
29421                            'expire' => 1800 // 30 minutes
29422                        ]);
29423                    }
29424                }
29425                // end NJ-20741
29426
29427                $paymentAmount = 0;
29428
29429                // get receivable reservation payment
29430                $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userId);
29431                if ($receivablePayment) {
29432                    $paymentAmount += $receivablePayment;
29433                }
29434
29435                // get appreciation receivable payments
29436                $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('appreciation_data.payment_element_type'));
29437                if ($appreciationReceivable) {
29438                    $paymentAmount += $appreciationReceivable;
29439                }
29440
29441                // - pay receivables
29442                if($paymentAmount && $individual_payment_card_empty == false){
29443                    $response['pay_receivables'] = 1;
29444                    // - payment transaction params
29445                    $paymentHash = myTools::generateOrderCode($userId);
29446                    $receivablePT = array(
29447                        'userId' => $userId,
29448                        'status' => 0,
29449                        'paymentHash' => $paymentHash,
29450                        'paymentParams' => json_encode(array(
29451                            'currencyCode' => $userData['currency_code'],
29452                            'formType' => Configure::read('payment_credit_receivable'),
29453                            'paymentType' => Configure::read('payment_types.payment_receivable'),
29454                            'paymentAmount' => $paymentAmount,
29455                            'paymentPlanId' => $userData['payment_plan_id'],
29456                            'priceId' => $userData['price_id']
29457                        )),
29458                        'responseText' => '',
29459                        'logFileName' => ''
29460                    );
29461
29462                    // - creating payment transaction
29463                    if (!$this->PaymentTransaction->rawSaveCronPaymentTransaction($receivablePT)) {
29464                        $response['error'] = true;
29465                        $response['msg'] = 'Error creating payment trasaction for receivable payments';
29466                        return json_encode($response);
29467                    }
29468
29469                    $zp_receivable_params = array(
29470                        'clientIp' => Configure::read('ZEUS_clientip'),
29471                        'email' => $userData['email'],
29472                        'sendId' => $userId,
29473                        'money' => $paymentAmount,
29474                        'paymentHash' => $paymentHash
29475                    );
29476    
29477                    $receivable_response = ZChargeComponent::charge_with_regsterd_card(json_encode($zp_receivable_params));
29478
29479                    // check if successful 
29480                    if ($receivable_response === "Success_order") {
29481                        $response['payment_status'] = 1;
29482                        $response['error'] = false;
29483                        $response['msg'] = 'Paying receivables';
29484                    } else {
29485                        $response['msg'] = 'Error Paying receivables';
29486                    }
29487
29488
29489                } else {
29490                    $response['error'] = false;
29491                    $response['msg'] = 'Successfully register card';
29492                }
29493                
29494            } else {
29495                $response['msg'] = 'Failed to register card';
29496            }
29497
29498            if(!$response['error']){
29499                $this->memcache->set(array(
29500                    'key' => 'register_or_charge_card_' . $userData['id'],
29501                    'value' => true,
29502                    'expire' => 3600 // 1 hour
29503                ));
29504            }
29505        }
29506
29507        return json_encode($response);
29508    }
29509    /**
29510     * @api {get} /mobapp/payment/corporate_user_change_personal_card_payment/:token/:cardToken mobapp_corporate_change_individual_card_payment()
29511     * @apiName mobapp_corporate_change_individual_card_payment
29512     * @apiGroup Payment
29513     * @apiDescription Change individual card payment for corporate user
29514     * 
29515     * @apiParam {String} token User token
29516     * @apiParam {String} cardToken Card token. Blank if not provided
29517     *  
29518     * @apiBody {Object[]} ZPaymentFullLogs The payment details.
29519     * @apiBody {Number} ZPaymentFullLogs.cardnumber The credit card number.
29520     * @apiBody {Number} ZPaymentFullLogs.expyy The expiration year of the credit card.
29521     * @apiBody {Number} ZPaymentFullLogs.expmm The expiration month of the credit card.
29522     * @apiBody {String} ZPaymentFullLogs.username The name on the credit card.
29523     * @apiBody {String} ZPaymentFullLogs.zeusTokenValue The token value for the credit card.
29524     * @apiBody {Number} ZPaymentFullLogs.payment_plan_type The payment plan type.
29525     * @apiBody {String} ZPaymentFullLogs.paymentHash The payment hash.
29526     * @apiBody {Number} ZPaymentFullLogs.money The payment amount.
29527     * @apiBody {Number} ZPaymentFullLogs.formType The form type. Is set to 2.
29528     * @apiBody {Number} ZPaymentFullLogs.retainIndiPlan The retain individual plan flag.\
29529     * @apiBody {String} ZPaymentFullLogs.telno The telephone number.
29530     * @apiBOdy {String} ZPaymentFulllogs.clientip The client IP address.
29531     * @apiBody {String} ZPaymentFullLogs.corporatePlan The corporate plan.
29532     * @apiBody {String} ZPaymentFullLogs.indiCorpType The individual corporate type. 4 for individual plan.
29533     * @apiBody {String} token The user token.
29534     * @apiBody {String} cardToken The card token.
29535     * @apiBody {Number} payment_gateway_type The payment gateway type. Default is 1 for zeus. 6 for paypal.
29536     * @apiBody {Object[]} [paymentPlanData] The payment plan data for paypal gateway.
29537     * @apiBody {String} [paymentPlanData.amount] The payment amount.
29538     * @apiBody {String} [paymentPlanData.priceId] The price ID.
29539     * @apiBody {String} [paymentPlanData.paymentPlanId] The payment plan ID.
29540     * @apiBody {Number} receivablePayment The receivable payment amount
29541     * @apiBody {Number} appreciationReceivable The appreciation receivable payment amount
29542     * @apiBody {Number} liveLessonReceivable The live lesson receivable payment amount
29543     * 
29544     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/mobapp_credit_charge_confirm for successful credit charge. 
29545     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/payment/paypal_payment_credit_charge_confirm for paypal success
29546     * 
29547     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage for failed credit charge / missing token.
29548     * 
29549     * @apiExample Example usage:
29550     * {
29551     *         "ZPaymentFullLogs": {
29552     *             "cardnumber": 1234567890123456,
29553     *             "expyy": 2022,
29554     *             "expmm": 12,
29555     *             "username": "John Doe",
29556     *             "zeusToken": "zeusTokenValue",
29557     *             "payment_plan_type": 1,
29558     *             "paymentHash": "paymentHash",
29559     *             "money": 100,
29560     *             "formType": 2,
29561     *             "retainIndiPlan": 1,
29562     *             "telno": "0363863975",
29563     *             "clientip": "192.168.1.1",
29564     *             "corporatePlan": "premium",
29565     *             "indiCorpType": 4
29566     *         },
29567     *         "token": "userToken",
29568     *         "cardToken": "cardToken",
29569     *         "payment_gateway_type": 1,
29570     *         "receivablePayment": 100,
29571     *         "appreciationReceivable": 100,
29572     *         "liveLessonReceivable": 100
29573     * }
29574     * 
29575     * @apiSuccessExample Success Response For zeus:
29576     * Redirects to {{ENV}}/mobapp/payment/mobapp_credit_charge_confirm
29577     * 
29578     * @apiSuccessExample Success Response For paypal:
29579     * Redirects to {{ENV}}/mobapp/payment/paypal_payment_credit_charge_confirm
29580     * 
29581     * @apiErrorExample Error Response:
29582     * Redirects to {{ENV}}/mobapp/retrypage
29583     * 
29584     * apiSampleRequest off
29585     */
29586    public function mobapp_corporate_change_individual_card_payment() {
29587        $this->response->disableCache();
29588        $this->blockWithdrawnSapuriToS('mobapp');
29589        $this->disablePageForSapuri('mobapp');
29590        // set variables
29591        $this->layout = 'mobapp';
29592        $urlParams = myTools::getMobappToken($_GET);
29593
29594        $logFileName = 'card_charge';
29595        $formType = Configure::read('payment_credit_force_charge');
29596        $userData = $this->mobappGetUserData(array('logFileName' => $logFileName, 'formType' => $formType)); // get user data and validate
29597        $requestQuery = $this->request->query;
29598        $apiToken = $requestQuery['token'];
29599        $paymentPlanId = Configure::read('payment_plans.premium_plan');
29600        $cardToken = isset($requestQuery['cardToken']) ? $requestQuery['cardToken'] : '';
29601        $memKey = 'mobappUserCreditChargeInfo_'.$apiToken;
29602        $userDataArr = $userData['User'];
29603        $corporateChargeMemData = array();
29604        $requestData = $this->request->data;
29605
29606        $userObj = new UserTable($userDataArr);
29607        $fromPage = !empty($this->request->query('from_page')) ? $this->request->query('from_page') : 'reservation';
29608        if (
29609            $fromPage != 'tip' && 
29610            !empty($userData['User']['corporate_id']) && 
29611            in_array($userObj->getMembershipTypeIndex(), Configure::read('common_corporate_payment_memberships'))
29612        ) {
29613            return $this->redirect(myTools::getUrl() . '/mobapp/common_corporate_payment?type=' .Configure::read('payment_url_type.corporate_type.corporate_change_individual_card_payment'). '&token=' . $apiToken . '&from_page=' . $fromPage);
29614        }
29615
29616        // - validate corp standard and premium user if bank and card
29617        if(!in_array($userObj->getMembershipTypeIndex(), Configure::read('corp_personal_card_payment_valid_memberships'))){
29618            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
29619        }
29620
29621        // get premium payment plan data
29622        $paymentData = $this->PaymentPlanPrice->getPaymentData(array(
29623            'currencyCode' => $userDataArr['currency_code'],
29624            'paymentPlanId' => $paymentPlanId,
29625            'logFileName' => $logFileName
29626        ));
29627
29628        if (!$paymentData) {
29629            return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
29630        }
29631
29632        $amount = $paymentData['amount'];
29633        $fAmount = $paymentData['fAmount'];
29634        $retainIndiPlan = null;
29635        $corporateIndiUser = false;
29636
29637        // if corporate user
29638        if (isset($userDataArr['corporate_id']) && $userDataArr['corporate_id'] && isset($userDataArr['payment_plan_id'])) {
29639            
29640            // NJ-28462 Organize the re-enrollment behavior after corporate plan end From bug ticket
29641            $cpData = $this->getCorporatePaymentPlan($userDataArr);
29642            if (!$cpData) {
29643                return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
29644            }
29645            $corporateIndiUser = $cpData;
29646
29647            // check if corporate user retain as individual plan using new card
29648            if (!$retainIndiPlan = isset($requestQuery['retainIndiPlan']) ? $requestQuery['retainIndiPlan'] : null) {
29649                // check if corporate user retain as individual plan using existing card
29650                $retainIndiPlan = isset($requestData['ZPaymentFullLogs']['retainIndiPlan']) ? $requestData['ZPaymentFullLogs']['retainIndiPlan'] : null;
29651            }
29652
29653            if ($retainIndiPlan) {
29654                // get corporate user individual payment plan data
29655                if ($corporateChargeMemData = $this->memcache->get('mobappCreditChargeCorporateData_' . $userDataArr['id'])) {
29656                    $formType = myTools::getCorporateCompanyCardFormType($corporateChargeMemData['paymentPlanId']);
29657                    $amount = (int)$corporateChargeMemData['paymentAmount'];
29658                    $fAmount = $corporateChargeMemData['fAmount'];
29659                }
29660            }
29661        }
29662
29663        // - set receivable 
29664        $receivablePayment =  $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id']);
29665
29666        // get live lesson payment receivable
29667        $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('appreciation_data.payment_element_type'));
29668
29669        // get live lesson payment receivable
29670        $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('payment_element_type.live'));
29671
29672        $mobappCorpIndividualData = array(
29673            'apiToken' => $apiToken,
29674        );
29675        $this->corpIndividualData($userDataArr,$mobappCorpIndividualData);
29676
29677        // check if post
29678        if ($this->request->is('post')) {
29679            $data = $this->request->data;
29680
29681            $isLitePlanFlg = false;
29682
29683            if (
29684                isset($data['ZPaymentFullLogs']['payment_plan_type']) && 
29685                !$corporateIndiUser
29686            ) {
29687
29688                $isLitePlan = $isLitePlanFlg = ((int) $data['ZPaymentFullLogs']['payment_plan_type']  == 1) ? true : false;
29689                if ($isLitePlan) {
29690                    $_plan_id = Configure::read('payment_plans.light_plan');
29691                    $formType = myTools::getLitePlanUserFormType($_plan_id);
29692                }else{
29693                    $_plan_id = Configure::read('payment_plans.premium_plan');
29694                    $formType = Configure::read('payment_credit_force_charge');
29695                }
29696
29697                // fetch light plan description
29698                $litePlanData = $this->PaymentPlanPrice->getPaymentData(array(
29699                    'currencyCode' => $userDataArr['currency_code'],
29700                    'paymentPlanId' => $_plan_id,
29701                    'logFileName' => 'card_reregister'
29702                ));
29703
29704                if (!$litePlanData) {
29705                    return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
29706                }
29707
29708                // update payment plan data 
29709                $paymentData = $litePlanData;
29710
29711                $userDataArr['paymentAmount'] = $paymentData['amount'];
29712                $userDataArr['price_id'] = $paymentData['priceId'];
29713                $userDataArr['payment_plan_id'] = $paymentData['paymentPlanId'];
29714
29715                // add reserve payment receivable
29716                $userDataArr['paymentAmount'] +=  $receivablePayment;
29717
29718                // add appreciation payment receivable
29719                $userDataArr['paymentAmount'] +=  $appreciationReceivable;
29720
29721                // add live lesson payment receivable
29722                $userDataArr['paymentAmount'] +=  $liveLessonReceivable;
29723            
29724            
29725                // - update form type 
29726                $data['formType'] = $formType;
29727
29728                // redirect to retry page if failed to create payment transaction
29729                if (!$npt = $this->createPaymentTransaction($formType, $userDataArr)) {
29730                    return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
29731                }
29732
29733                // update payment hash , form type and money
29734                $data['ZPaymentFullLogs']['paymentHash'] = $npt['payment_hash'];
29735                $data['ZPaymentFullLogs']['money'] = $litePlanData['amount'];
29736                $data['ZPaymentFullLogs']['formType'] = $formType;
29737
29738            }else{
29739                $npt = true;
29740            }
29741
29742            if (
29743                $corporateIndiUser && 
29744                isset($data['ZPaymentFullLogs']['payment_plan_type']) && 
29745                (int) $data['ZPaymentFullLogs']['payment_plan_type'] == 1
29746            ) {
29747    
29748                $isLitePlanFlg = true;
29749
29750                $_plan_id = Configure::read('payment_plans.light_plan');
29751                $formType = myTools::getLitePlanUserFormType($_plan_id);
29752
29753                $data['token'] = $apiToken;
29754                $data['ZPaymentFullLogs']['telno'] = Configure::read('credit.default_telno');
29755                $data['ZPaymentFullLogs']['clientip'] = Configure::read('ZEUS_clientip');
29756                $data['ZPaymentFullLogs']['corporatePlan'] = $data['corporatePlan'];
29757                $data['cardToken'] = $cardToken;
29758
29759                if($corporateIndiUser['corporateIndiUser'] && isset($data['corporatePlan'])) {
29760                    if($data['corporatePlan'] == 'light') {
29761                        $cpData = $this->getCorporatePaymentPlan($userDataArr,array('corporate_type' => 4));
29762                        $data['ZPaymentFullLogs']['indiCorpType'] = 4;
29763                    } else if($data['corporatePlan'] == 'premium') {
29764                        $cpData = $this->getCorporatePaymentPlan($userDataArr,array('corporate_type' => 2));
29765                        $data['ZPaymentFullLogs']['indiCorpType'] = 2;
29766                    } else {
29767                        $cpData = $this->getCorporatePaymentPlan($userDataArr,array('corporate_type' => 1));
29768                        $data['ZPaymentFullLogs']['indiCorpType'] = 1;
29769                    }
29770                    $data['ZPaymentFullLogs']['formType'] = $formType = myTools::getCorporateCompanyCardFormType($cpData['paymentPlanId']);
29771                    $corpIndiPrices = $this->memcache->get('mobappcorporateIndiPrices_'.$userDataArr['api_token']);
29772                    $corpIndiPrices[$data['corporatePlan']]['plan_type'] = $data['ZPaymentFullLogs']['indiCorpType'];
29773                    $amount = (int)$corpIndiPrices[$data['corporatePlan']]['paymentAmount'];
29774                    $fAmount = $corpIndiPrices[$data['ZPaymentFullLogs']['corporatePlan']]['fAmount'];
29775    
29776                    $this->memcache->set(array(
29777                        'key' => 'mobappCreditChargeCorporateData_' . $userDataArr['id'],
29778                        'value' => $corpIndiPrices[$data['ZPaymentFullLogs']['corporatePlan']],
29779                        'expire' => 3600 // 1 hour
29780                    ));
29781    
29782                    $corporateChargeMemData = $this->memcache->get('mobappCreditChargeCorporateData_' . $userDataArr['id']);
29783    
29784                    // corporate light
29785                    if (
29786                        $corporateChargeMemData['plan_type'] == Configure::read('corporate_type.light') &&
29787                        isset($corporateChargeMemData['lessonFee']) &&
29788                        isset($corporateChargeMemData['basicFee'])
29789                    ) {
29790                        $userDataArr['lesson_fee'] = (int)$corporateChargeMemData['lessonFee'];
29791                        $userDataArr['basic_fee'] = (int)$corporateChargeMemData['basicFee'];
29792                    // standard or premium
29793                    } else {
29794                        if (isset($corporateChargeMemData['cprAmount']) && isset($corporateChargeMemData['cprDiscount'])) {
29795                            $userDataArr['cprAmount'] = (int)$corporateChargeMemData['cprAmount'];
29796                            $userDataArr['cprDiscount'] = (int)$corporateChargeMemData['cprDiscount'];
29797                        }
29798                    }
29799    
29800                    $userDataArr['corporateSettlementType'] = Configure::read('corporate_settlement_types.force_charge_payment');
29801                    $userDataArr['paymentAmount'] = $amount;
29802                    $userDataArr['price_id'] = $cpData['priceId'];
29803                    $userDataArr['payment_plan_id'] = $cpData['paymentPlanId'];
29804                    $userDataArr['corporate_type'] = $data['ZPaymentFullLogs']['indiCorpType'];
29805                    $formType = myTools::getCorporateCompanyCardFormType($cpData['paymentPlanId']);
29806    
29807                    $membershipTypes = UserTable::getEngMembershipTypeData();
29808                    $userDataArr['statusAfter'] =  myTools::getCorporateUserMembershipStatusName($membershipTypes, $userDataArr['payment_plan_id']);
29809    
29810                    $userTable = new UserTable($userDataArr);
29811                    // add statusBefore and statusAfter if free "Trial not yet conducted"
29812                    if ($userTable->getMembershipTypeIndex() == 13) {
29813                        $userDataArr['statusBefore'] = $membershipTypes[13];
29814                        $userDataArr['statusAfter'] = myTools::getCorporateUserMembershipStatusName($membershipTypes, $userDataArr['payment_plan_id']);
29815                    }
29816    
29817                    if ($retainIndiPlan) {
29818                        $data['ZPaymentFullLogs']['retainIndiPlan'] = $retainIndiPlan;
29819                    }
29820    
29821                    if ($corporateIndiUser && $corporateChargeMemData) {
29822                        // save new card charge token to memcache
29823                        $this->memcache->set(array(
29824                            'key' => 'card-charge-'.$apiToken,
29825                            'value' => $cardToken,
29826                            'expire' => 3600
29827                        ));
29828                    }
29829    
29830                    // add reserve payment receivable
29831                    $userDataArr['paymentAmount'] +=  $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id']);
29832    
29833                    // add appreciation payment receivable
29834                    $userDataArr['paymentAmount'] +=  $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('appreciation_data.payment_element_type'));
29835    
29836                    // add live lesson payment receivable
29837                    $userDataArr['paymentAmount'] +=  $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('payment_element_type.live'));
29838    
29839                    // redirect to retry page if failed to create payment transaction
29840                    if (!$pt = $this->createPaymentTransaction($formType, $userDataArr)) {
29841                        return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
29842                    }
29843    
29844                    $data['ZPaymentFullLogs']['paymentHash'] = $pt['payment_hash'];
29845    
29846                } // End of Check Corporate Individual
29847
29848                // NJ-25522: Skip confirm page if using 3D secure challenge
29849                $zeus3DSecureChallengeFlg = $this->memcache->get('zeus3DSecureChallengeFlg_' . $userDataArr['id']);
29850
29851                if ($zeus3DSecureChallengeFlg) {
29852                    // unset previously set tokens
29853                    $this->unsetTokenMobapp($apiToken, 'card-charge-');
29854
29855                    $formType = isset($data['ZPaymentFullLogs']['formType']) ? $data['ZPaymentFullLogs']['formType'] : $formType;
29856
29857                    // if corporate credit charge
29858                    if (
29859                        $formType != Configure::read('payment_credit_force_charge') && 
29860                        !$isLitePlanFlg
29861                    ) {
29862                        $data['ZPaymentFullLogs']['money'] = $fAmount;
29863                    }
29864
29865                    $totalReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id']) + $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('appreciation_data.payment_element_type')) + $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('payment_element_type.live'));
29866
29867                    $data['ZPaymentFullLogs']['money'] += $totalReceivable;
29868                    $this->Session->write('mobapp_show_welcome_back_modal',true);
29869                    //process zeus card
29870                    $this->zeus_card_process_mobapp(array(
29871                        'data' => $data,
29872                        'form_type' => $formType,
29873                        'referrer' => array('controller' => 'Payment', 'action' => 'mobapp_credit_charge', '?' => array('token' => $apiToken)),
29874                        'api_token' => $apiToken
29875                    ));
29876                }
29877
29878                // delete memcache if exist
29879                if ($this->memcache->get($memKey)) {
29880                    $this->memcache->delete($memKey);
29881                }
29882
29883                // set memcache
29884                $this->memcache->set(array(
29885                    'key' => $memKey,
29886                    'value' => $data,
29887                    'expire' => 3600
29888                ));
29889                
29890                // fetch light plan description
29891                $litePlanData = $this->PaymentPlanPrice->getPaymentData(array(
29892                    'currencyCode' => $userDataArr['currency_code'],
29893                    'paymentPlanId' => $_plan_id,
29894                    'logFileName' => $logFileName
29895                ));
29896
29897                if (!$litePlanData) {
29898                    return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
29899                }
29900
29901                // update payment plan data 
29902                $paymentData = $litePlanData;
29903
29904                $userDataArr['paymentAmount'] = $paymentData['amount'];
29905                $userDataArr['price_id'] = $paymentData['priceId'];
29906                $userDataArr['payment_plan_id'] = $paymentData['paymentPlanId'];
29907
29908                // add reserve payment receivable
29909                $userDataArr['paymentAmount'] +=  $receivablePayment;
29910
29911
29912                // add appreciation payment receivable
29913                $userDataArr['paymentAmount'] +=  $appreciationReceivable;
29914
29915                // add live lesson payment receivable
29916                $userDataArr['paymentAmount'] +=  $liveLessonReceivable;
29917            
29918            
29919                // - update form type 
29920                $data['formType'] = $formType;
29921                
29922                // redirect to retry page if failed to create payment transaction
29923                if (!$npt = $this->createPaymentTransaction($formType, $userDataArr)) {
29924                    return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
29925                }
29926
29927                // update payment hash
29928                $data['ZPaymentFullLogs']['paymentHash'] = $npt['payment_hash'];
29929                $data['ZPaymentFullLogs']['formType'] = $formType;
29930                $data['ZPaymentFullLogs']['money'] = $litePlanData['amount'];
29931                $data['ZPaymentFullLogs']['retainIndiPlan'] = 0;
29932            }
29933
29934
29935                
29936            // redirect to paypal confirm page if payment gateway selected is paypal
29937            if ($data['payment_gateway_type'] == Configure::read('card_company.paypal')) {
29938                $data['paymentPlanData'] = $paymentData;
29939                $data['receivablePayment'] = $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id']);
29940                $data['appreciationReceivable'] = $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('appreciation_data.payment_element_type'));
29941                $data['liveLessonReceivable'] = $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('payment_element_type.live'));
29942                $data['formType'] = $formType;
29943                $this->memcache->set(array(
29944                    'key' => 'mobappPaypalPaymentCreditChargeData_' . $apiToken,
29945                    'value' => $data,
29946                    'expire' => 3600 // 1 hour
29947                ));
29948                return $this->redirect(myTools::getUrl() . '/mobapp/payment/paypal_payment_credit_charge_confirm?token=' . $apiToken);
29949            }
29950
29951            // delete payment gateway type memcache
29952            $this->memcache->delete('mobappCreditChargePaymentGatewayType_' . $apiToken);
29953
29954            $data['token'] = $apiToken;
29955            $data['ZPaymentFullLogs']['telno'] = Configure::read('credit.default_telno');
29956            $data['ZPaymentFullLogs']['clientip'] = Configure::read('ZEUS_clientip');
29957            $data['cardToken'] = $cardToken;
29958
29959            // NJ-25522: Skip confirm page if using 3D secure challenge
29960            $zeus3DSecureChallengeFlg = $this->memcache->get('zeus3DSecureChallengeFlg_' . $userDataArr['id']);
29961
29962            if ($zeus3DSecureChallengeFlg) {
29963                // unset previously set tokens
29964                $this->unsetTokenMobapp($apiToken, 'card-charge-');
29965
29966                $formType = isset($data['ZPaymentFullLogs']['formType']) ? $data['ZPaymentFullLogs']['formType'] : $formType;
29967
29968                // if corporate credit charge
29969                if (
29970                        $formType != Configure::read('payment_credit_force_charge') && 
29971                        !$isLitePlanFlg
29972                ) {
29973                    $data['ZPaymentFullLogs']['money'] = $fAmount;
29974                }
29975
29976                $totalReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id']) + $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('appreciation_data.payment_element_type')) + $this->PaymentReceivable->computeReceivableReservationPayment($userDataArr['id'], false, Configure::read('payment_element_type.live'));
29977
29978                $data['ZPaymentFullLogs']['money'] += $totalReceivable;
29979                $this->Session->write('mobapp_show_welcome_back_modal',true);
29980                //process zeus card
29981                $this->zeus_card_process_mobapp(array(
29982                    'data' => $data,
29983                    'form_type' => $formType,
29984                    'referrer' => array('controller' => 'Payment', 'action' => 'mobapp_credit_charge', '?' => array('token' => $apiToken)),
29985                    'api_token' => $apiToken
29986                ));
29987            }
29988
29989            // delete memcache if exist
29990            if ($this->memcache->get($memKey)) {
29991                $this->memcache->delete($memKey);
29992            }
29993
29994            // set memcache
29995            $this->memcache->set(array(
29996                'key' => $memKey,
29997                'value' => $data,
29998                'expire' => 3600
29999            ));
30000
30001            return $this->redirect(myTools::getUrl() . '/payment/mobapp_credit_charge_confirm'.$urlParams);
30002            
30003        } else {
30004            // delete payment gateway type memcache
30005            $this->memcache->delete('mobappCreditChargePaymentGatewayType_' . $apiToken);
30006
30007            $this->set('data', $this->memcache->get($memKey));
30008        }
30009
30010        // if not retain indi plan
30011        if (!$corporateIndiUser) {
30012            $userDataArr['paymentAmount'] = $paymentData['amount'];
30013            $userDataArr['price_id'] = $paymentData['priceId'];
30014            $userDataArr['payment_plan_id'] = $paymentData['paymentPlanId'];
30015
30016            $data['ZPaymentFullLogs']['formType'] = $formType;
30017
30018            // add reserve payment receivable
30019            $userDataArr['paymentAmount'] +=  $receivablePayment;
30020
30021            // add appreciation payment receivable
30022            $userDataArr['paymentAmount'] +=  $appreciationReceivable;
30023
30024            // add live lesson payment receivable
30025            $userDataArr['paymentAmount'] +=  $liveLessonReceivable;
30026
30027            // redirect to retry page if failed to create payment transaction
30028            if (!$pt = $this->createPaymentTransaction($formType, $userDataArr)) {
30029                return $this->redirect(myTools::getUrl() . '/mobapp/retrypage'.$urlParams);
30030            }
30031
30032            $data['ZPaymentFullLogs']['paymentHash'] = $pt['payment_hash'];
30033
30034        }
30035
30036        // delete memcache if exist
30037        if ($this->memcache->get($memKey)) {
30038            $this->memcache->delete($memKey);
30039        }
30040
30041        // set memcache
30042        $this->memcache->set(array(
30043            'key' => $memKey,
30044            'value' => $data,
30045            'expire' => 3600
30046        ));
30047
30048        $users_detail = $userObj->individualCardFailFlg();
30049        $this->set('individual_card_fail_flg', $users_detail['individual_card_fail_flg'] ?? 0);
30050        $this->getAndSetCardInfo($userDataArr);
30051        $this->setSupportPayPal($userDataArr);
30052        $this->set('userData', $userDataArr);
30053        $this->set('apiToken', $apiToken);
30054        $this->set('zeusTransactionFlag', true);
30055        $this->set('title_for_layout', '再入会');
30056        $this->set('paypalUserData', $userDataArr);
30057        $this->set('userApiToken', $apiToken);
30058        $this->render(myTools::getDeviceUrl().'Payment/corporate_change_individual_card_payment');
30059    }
30060
30061    /**
30062     * ~NJ-29078 - process child receivable payment 
30063     * @param array $familyArr, array $parentArr
30064     */
30065    public function processChildReceivablePayment($familyArr = [], $parentArr = []) {
30066        $this->logFileName = 'family_plan';
30067        $curlPayment = "";
30068
30069        if (!$pt = $this->Payment->setUpWithdrawTransaction($familyArr, $this->logFileName)) {
30070            return false;
30071        }
30072
30073        // ~if zero receivable just return success
30074        if (isset($pt['totalAmount']) && $pt['totalAmount'] == 0) {
30075            $this->log(__METHOD__ . ' No receivable to process' . json_encode($pt), $this->logFileName);
30076            $curlPayment = "success_order";
30077            return $curlPayment;
30078        }
30079
30080        $familyObj = new UserTable($familyArr);
30081        $parentObj = new UserTable($parentArr);
30082
30083        if ($parentObj->card_company == Configure::read('card_company.zeus')){
30084            $data = array(
30085                'clientIp' => PaymentTable::getClientIpByCompanyId($parentObj->card_company),
30086                'email' => $parentObj->email,
30087                'sendId' => $parentObj->id,
30088                'money' => $pt['totalAmount'],
30089                'paymentHash' => $pt['payment_hash']
30090            );
30091            // ~process
30092            $curlPayment = $this->ZCharge->charge_with_regsterd_card(json_encode($data));
30093            $curlPayment = PaymentTable::checkPaymentResult($curlPayment);
30094        } else if ($parentObj->card_company == Configure::read('card_company.worldpay')) {
30095            $paymentMethodType = myTools::getWPPaymentMethodType($parentObj->card_brand, 'payment');
30096            $merchantCode = myTools::getWPMerchantCode($paymentMethodType);
30097            $paymentHash = $pt['payment_hash'];
30098            $paymentMethod = explode('_', $paymentMethodType);
30099            $paymentMethod = isset($paymentMethod[0]) ? $paymentMethod[0] : null;
30100            $currencyExponents = Configure::read('worldpay.currency_exponents');
30101            $exponent = $currencyExponents[$parentObj->currency_code];
30102            // get amount with checking currency exponent
30103            $amountArr = myTools::wpGetAmount($exponent, $pt['totalAmount']);
30104            $wpAmount = $amountArr['wpAmount'];
30105
30106            $decodePaymentParams= json_decode($pt['payment_params']);
30107            $paymentFormType = $decodePaymentParams->formType;
30108
30109            $wpParams = array(
30110                'merchantCode' => $merchantCode,
30111                'orderCode' => $paymentHash,
30112                'description' => 'Child Withdrawal Receivables',
30113                'currencyCode' => $parentObj->currency_code,
30114                'exponent' => $exponent,
30115                'amount' => $wpAmount,
30116                'cardToken' => $parentObj->card_token,
30117                'email' => $parentObj->email,
30118                'authenticatedShopperId' => $parentObj->id,
30119                'xmlName' => 'direct_payment_with_token',
30120                'shopperIpAddress' => $_SERVER["REMOTE_ADDR"],
30121                'wpTransactionIdentifier' => $parentObj->wp_transaction_identifier,
30122                'paymentMethod' => $paymentMethod
30123            );
30124
30125            $updateData = array(
30126                'id' => $pt['id'],
30127                'fields' => array('payment_params' => $wpParams)
30128            );
30129
30130            if (!$this->PaymentTransaction->updateWPPaymentTransaction($updateData)) {
30131                $this->log(__METHOD__ . ' Failed to update payment transaction' . json_encode($updateData), $this->logFileName);
30132                $this->log(__METHOD__ . ' Worldpay: ' . $parentObj->id . ' - Failed to update payment transaction --> ' . json_encode($updateData), 'error');
30133            } else {
30134                if (!$pt = $this->PaymentTransaction->getWPPaymentTransaction($paymentHash)) {
30135                    return false;
30136                }
30137            }
30138
30139            $this->log(__METHOD__ . ' Worldpay: ' . $parentObj->id . ' - Initial updateWPPaymentTransaction --> ' . json_encode($updateData), 'error');
30140
30141            // ~process
30142            $res = wpPaymentService::directPayment($wpParams);
30143
30144            $updateData = array(
30145                'id' => $pt['id'],
30146                'fields' => array('response_text' => array('directPayment_response' => $res))
30147            );
30148
30149            if (!$this->PaymentTransaction->updateWPPaymentTransaction($updateData)) {
30150                $this->log(__METHOD__ . ' Failed to update payment transaction' . json_encode($updateData), $this->logFileName);
30151                $this->log(__METHOD__ . ' Worldpay: ' . $parentObj->id . ' - Failed to update payment transaction --> ' . json_encode($updateData), 'error');
30152            } else {
30153                $this->log(__METHOD__ . ' Worldpay: ' . $parentObj->id . ' - additional updateWPPaymentTransaction --> ' . json_encode($updateData), 'error');
30154            }
30155            
30156            if (!myTools::checkIfWPPaymentResponseIsAuthorised($res)) {
30157                $curlPayment = "";
30158                $this->log(__METHOD__ . ' Not authorised payment worldpay' . $familyObj->id, $this->logFileName);
30159                $this->log(__METHOD__ . ' Worldpay: ' . $parentObj->id . ' - Not authorised payment worldpay --> ' . $familyObj->id, 'error');
30160            }else{
30161                $curlPayment = "success_order";
30162            }
30163        } else if ($parentObj->card_company == Configure::read('card_company.aftee')) {
30164            $paymentMethodType = myTools::getWPPaymentMethodType($parentObj->card_brand, 'payment');
30165            $merchantCode = myTools::getWPMerchantCode($paymentMethodType);
30166            $paymentHash = $pt['payment_hash'];
30167            $paymentMethod = explode('_', $paymentMethodType);
30168            $paymentMethod = isset($paymentMethod[0]) ? $paymentMethod[0] : null;
30169            $decodePaymentParams= json_decode($pt['payment_params']);
30170            $paymentFormType = $decodePaymentParams->formType;          
30171
30172            $afteeParams = array(
30173                'merchantCode' => $merchantCode,
30174                'orderCode' => $paymentHash,
30175                'description' => 'Family Plan Registration',
30176                'currencyCode' => $parentObj->currency_code,
30177                'amount' => $pt['totalAmount'],
30178                'cardToken' => $parentObj->card_token,
30179                'email' => $parentObj->email,
30180                'authenticatedShopperId' => $parentObj->id,
30181                'shopperIpAddress' => $_SERVER["REMOTE_ADDR"],
30182                'afteeTransactionIdentifier' => $parentObj->aftee_transaction_identifier,
30183                'paymentMethod' => $paymentMethod
30184            );
30185
30186            $updateData = array(
30187                'id' => $pt['id'],
30188                'fields' => array('payment_params' => $afteeParams)
30189            );
30190
30191            if (!$this->PaymentTransaction->updateAfteePaymentTransaction($updateData)) {
30192                $this->log(__METHOD__ . ' Failed to update payment transaction' . json_encode($updateData), $this->logFileName);
30193            }else{
30194                if (!$pt = $this->PaymentTransaction->getAfteePaymentTransaction($paymentHash)) {
30195                    return false;
30196                }
30197            }
30198
30199            // ~process
30200            $afteeParams = array(
30201                'parent' =>  $parentObj,
30202                'child' =>  $familyObj,
30203                'paymentTransaction' => $pt,
30204                'appreciationFlg' => $familyObj->allow_appreciation_flg,
30205                'tipAmount' => myTools::stringToFloat($familyObj->tip_max_amount)
30206            );
30207
30208            $curlPayment = $this->processChildAfteePayment($afteeParams);
30209        } elseif ($parentObj->card_company == Configure::read('card_company.paypal')) {
30210            $paypalParams = array(
30211                'parent' => $parentObj,
30212                'child' => $familyObj,
30213                'paymentTransaction' => $pt,
30214                'memberStatus' => 'exist'
30215            );
30216
30217            $curlPayment = $this->processChildPaypalPayment($paypalParams);
30218        }
30219
30220        return $curlPayment;
30221    }
30222
30223    // ~NJ-29078 - Process Paypal Payment
30224    private function processChildPaypalPayment($params = array()) {
30225        if (
30226            !isset($params['child']) ||
30227            !isset($params['parent']) ||
30228            !isset($params['paymentTransaction'])
30229        ) {
30230            $this->log('__METHOD__' . ' missing parameter(s). --> ' . json_encode($params), $this->logFileName);
30231            return false;
30232        }
30233
30234        // ~check for family parent 
30235        $child = $params['child'];
30236        $parent = $params['parent'];
30237        $pt = $params['paymentTransaction'];
30238        $memberStatus = $params['memberStatus'];
30239
30240        $paymentHash = $pt['payment_hash'];
30241        $ptPassword = $pt['password'];
30242        $ptParams = json_decode($pt['payment_params'], true);
30243
30244        $formType = $ptParams['formType'];
30245        $currencyCode = $ptParams['currencyCode'];
30246        $paymentPlanId = $ptParams['paymentPlanId'];
30247        $priceId = $ptParams['priceId'];
30248        $paymentType = Configure::read('payment_types.payment_receivable');
30249        $platform = $ptParams['platform'];
30250
30251        $membershipStatusIndex = UserTable::getStudentMembershipStatus($child->id);
30252        $currencyId = Configure::read('default.settlement_currency_id'); // set currency id to jpy
30253        $cardCompany = Configure::read('card_company.paypal');
30254        $dateTimeNow = date('Y-m-d H:i:s');
30255
30256        $reservationReceivableAmount = isset($ptParams['reservationReceivableAmount']) ? $ptParams['reservationReceivableAmount'] : 0;
30257        $appreciationReceivableAmount = isset($ptParams['appreciationReceivableAmount']) ? $ptParams['appreciationReceivableAmount'] : 0;
30258        $liveReceivableAmount = isset($ptParams['liveReceivableAmount']) ? $ptParams['liveReceivableAmount'] : 0;
30259
30260
30261        if (!class_exists('PayPal')) {
30262            App::import('Lib', 'PayPal');
30263        }
30264
30265        $PayPal = new PayPal();
30266        $accessTokenData = $PayPal->getAccessToken();
30267
30268        $totalAmount = (int) ($reservationReceivableAmount + $appreciationReceivableAmount + $liveReceivableAmount);
30269
30270        $paypalParams = array(
30271            'ptId' => $pt['id'],
30272            'paypalData' => array('accessTokenData' => $accessTokenData),
30273            'userId' => $pt['id'],
30274            'money' => $totalAmount,
30275            'formType' => $formType,
30276            'priceId' => $priceId,
30277            'paymentId' => $paymentPlanId,
30278            'paymentType' => $paymentType
30279        );
30280
30281        // break if error
30282        if (!isset($accessTokenData['access_token'])) {
30283                $this->log(__METHOD__ . ' paypal error --> ' . json_encode($accessTokenData) . ' --> ' . json_encode($params), $this->logFileName);
30284            return ;
30285        }
30286
30287        $createOrderParams = array(
30288            'accessToken' => $accessTokenData['access_token'],
30289            'paypalRequestId' => $pt['id'],
30290            'intent' => 'CAPTURE',
30291            'paymentHash' => $paymentHash,
30292            'userId' => $parent->id,
30293            'currencyCode' => $currencyCode,
30294            'amount' => $totalAmount,
30295            'billingAgreementId' => $parent->paypal_billing_agreement_id
30296        );
30297
30298        // add mock application code
30299        if (isset($request['mockResponse'])) {
30300            $createOrderParams['mockResponse'] = $request['mockResponse'];
30301        }
30302
30303        $curlPayment = $PayPal->createOrder($createOrderParams);
30304        $paypalParams['paypalData']['createOrder'] = $curlPayment;
30305        $paymentSuccess = isset($curlPayment['status']) && $curlPayment['status'] == 'COMPLETED' ? true : false;
30306
30307        if (!$paymentSuccess) {
30308            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $parent->id, 'Paypal process child payment - failed to create order', $ptParams, $createOrderParams);
30309            $this->log(__METHOD__ . ' paypal error --> ' . json_encode($curlPayment) . ' --> ' . json_encode($params), $this->logFileName);
30310            return ;
30311        }
30312
30313        // create payment
30314        $savePaymentArr = array(
30315            'user_id' => $child->id,
30316            'amount' => $totalAmount,
30317            'status' => 1,
30318            'reference_id' => $child->id,
30319            'payment_transaction_password' => $ptPassword,
30320            'card_company' => $cardCompany,
30321            'param1' => json_encode($paypalParams),
30322            'form_type' => $formType,
30323            'ordd' => $paymentHash,
30324            'transaction_code' => $paymentHash,
30325            'currency_id' => $currencyId,
30326            'currency_code' => $currencyCode,
30327            'payment_id' => $paymentPlanId,
30328            'price_id' => $priceId,
30329            'payment_type' => $paymentType
30330        );
30331
30332        $this->Payment->clear();
30333        $this->Payment->create();
30334        $this->Payment->set($savePaymentArr);
30335        $this->Payment->validate = array();
30336
30337        // update/add user`s settlement amount
30338        $this->User->updateUserPayments($savePaymentArr);
30339
30340        // set payment_id
30341        $paymentSaveID = $this->Payment->id;
30342        $data = array('payment_id' => $paymentSaveID);
30343        $paymentType = Configure::read('payment_types.payment_receivable');
30344
30345        // reservation receivable
30346        if ($reservationReceivableAmount > 0) {
30347            $savePaymentArr = array(
30348                'user_id' => $child->id,
30349                'amount' => $reservationReceivableAmount,
30350                'status' => 1,
30351                'type_id' => 1,
30352                'reference_id' => $child->id,
30353                'card_company' => $cardCompany,
30354                'param1' => json_encode($data),
30355                'form_type' => Configure::read('payment_credit_receivable'),
30356                'ordd' => $paymentHash,
30357                'transaction_code' => $paymentHash,
30358                'currency_id' => $currencyId,
30359                'currency_code' => $currencyCode,
30360                'payment_id' => $paymentPlanId,
30361                'price_id' => $priceId,
30362                'payment_type' => $paymentType
30363            );
30364
30365            // create new payment for reservation receivable
30366            $this->Payment->clear();
30367            $this->Payment->create();
30368            $this->Payment->set($savePaymentArr);
30369            if (!$this->Payment->save()) {
30370                $this->log(__METHOD__ . ' Failed to save payment data for reservation receivable.' . json_encode($savePaymentArr), $logFileName);
30371                $dataSource->rollback();
30372                return ;
30373            }
30374
30375            // set payment_id
30376            $rrPaymentID = $this->Payment->id;
30377
30378            //update/add user`s settlement amount
30379            $this->User->updateUserPayments($savePaymentArr);
30380
30381            // set payment receivable statuses to 2 - received
30382            $this->PaymentReceivable->updateReceivableReservationPayment(
30383                $child->id,
30384                array(
30385                    'status' => 2,
30386                    'payment_id' => $rrPaymentID,
30387                    'payment_collection_date' => $dateTimeNow,
30388                    'card_company' => $cardCompany,
30389                    'payment_plan_id' => $paymentPlanId,
30390                    'membership_type_index' => $membershipStatusIndex
30391                ),
30392                array(
30393                    'PaymentReceivable.user_id' => $child->id,
30394                    'PaymentReceivable.status' => 0,
30395                    'PaymentReceivable.payment_element_type' => Configure::read('payment_element_type.reservation'),
30396                    'PaymentReceivable.created <=' => $dateTimeNow
30397                )
30398            );
30399        }
30400
30401        // appreciation receivable
30402        if ($appreciationReceivableAmount > 0) {
30403            $savePaymentArr = array(
30404                'user_id' => $child->id,
30405                'amount' => $appreciationReceivableAmount,
30406                'status' => 1,
30407                'type_id' => 1,
30408                'reference_id' => $child->id,
30409                'card_company' => $cardCompany,
30410                'param1' => json_encode($data),
30411                'form_type' => Configure::read('payment_credit_appreciation_receivable'),
30412                'ordd' => $paymentHash,
30413                'transaction_code' => $paymentHash,
30414                'currency_id' => $currencyId,
30415                'currency_code' => $currencyCode,
30416                'payment_id' => $paymentPlanId,
30417                'price_id' => $priceId,
30418                'payment_type' => $paymentType
30419            );
30420
30421            // create new payment for appreciation receivable
30422            $this->Payment->clear();
30423            $this->Payment->create();
30424            $this->Payment->set($savePaymentArr);
30425            if (!$this->Payment->save()) {
30426                $this->log(__METHOD__ . ' Failed to save payment data for appreciation receivable.' . json_encode($savePaymentArr), $logFileName);
30427                $dataSource->rollback();
30428                return ;
30429            }
30430
30431            // set payment_id
30432            $arPaymentID = $this->Payment->id;
30433
30434            //update/add user`s settlement amount
30435            $this->User->updateUserPayments($savePaymentArr);
30436
30437            // set payment receivable statuses to 2 - received
30438            $this->PaymentReceivable->updateReceivableReservationPayment(
30439                $child->id,
30440                array(
30441                    'status' => 2,
30442                    'payment_id' => $arPaymentID,
30443                    'payment_collection_date' => $dateTimeNow,
30444                    'card_company' => $cardCompany,
30445                    'payment_plan_id' => $paymentPlanId,
30446                    'membership_type_index' => $membershipStatusIndex
30447                ),
30448                array(
30449                    'PaymentReceivable.user_id' => $child->id,
30450                    'PaymentReceivable.status' => 0,
30451                    'PaymentReceivable.payment_element_type' => Configure::read('payment_element_type.appreciation'),
30452                    'PaymentReceivable.created <=' => $dateTimeNow
30453                )
30454            );
30455        }
30456
30457        // live receivable
30458        if ($liveReceivableAmount > 0) {
30459            $savePaymentArr = array(
30460                'user_id' => $child->id,
30461                'amount' => $liveReceivableAmount,
30462                'status' => 1,
30463                'type_id' => 1,
30464                'reference_id' => $child->id,
30465                'card_company' => $cardCompany,
30466                'param1' => json_encode($data),
30467                'form_type' => Configure::read('payment_live_lesson_receivable'),
30468                'ordd' => $paymentHash,
30469                'transaction_code' => $paymentHash,
30470                'currency_id' => $currencyId,
30471                'currency_code' => $currencyCode,
30472                'payment_id' => $paymentPlanId,
30473                'price_id' => $priceId,
30474                'payment_type' => $paymentType
30475            );
30476
30477            // create new payment for live receivable
30478            $this->Payment->clear();
30479            $this->Payment->create();
30480            $this->Payment->set($savePaymentArr);
30481            if (!$this->Payment->save()) {
30482                $this->log(__METHOD__ . ' Failed to save payment data for live receivable.' . json_encode($savePaymentArr), $logFileName);
30483                $dataSource->rollback();
30484                return ;
30485            }
30486
30487            // set payment_id
30488            $lrPaymentID = $this->Payment->id;
30489
30490            //update/add user`s settlement amount
30491            $this->User->updateUserPayments($savePaymentArr);
30492
30493            // set payment receivable statuses to 2 - received
30494            $this->PaymentReceivable->updateReceivableReservationPayment(
30495                $child->id,
30496                array(
30497                    'status' => 2,
30498                    'payment_id' => $lrPaymentID,
30499                    'payment_collection_date' => $dateTimeNow,
30500                    'card_company' => $cardCompany,
30501                    'payment_plan_id' => $paymentPlanId,
30502                    'membership_type_index' => $membershipStatusIndex
30503                ),
30504                array(
30505                    'PaymentReceivable.user_id' => $child->id,
30506                    'PaymentReceivable.status' => 0,
30507                    'PaymentReceivable.payment_element_type' => Configure::read('payment_element_type.live'),
30508                    'PaymentReceivable.created <=' => $dateTimeNow
30509                )
30510            );
30511        }
30512
30513        $fields = array('status' => 1);
30514        if (isset($paypalParams)) {
30515            $fields['response_text'] = array('paypal_response' => $paypalParams);
30516        }
30517
30518        // update payment transaction
30519        $this->PaymentTransaction->updateWPPaymentTransaction(array('id' => $ptId, 'fields' => $fields));
30520
30521        return 'success_order';
30522
30523    }
30524    
30525    // ~NJ-29078 - Process Aftee Payment
30526    private function processChildAfteePayment($params = array()) {
30527        if (
30528            !isset($params['child']) ||
30529            !isset($params['parent']) ||
30530            !isset($params['paymentTransaction'])
30531        ) {
30532            $this->log('__METHOD__' . ' missing parameter(s). --> ' . json_encode($params), $this->logFileName);
30533            return false;
30534        }
30535
30536        $parent = $params['parent'];
30537        $child = $params['child'];
30538        $pt = $params['paymentTransaction'];
30539
30540        $ptId = $pt['id'];
30541        $ptPassword = $pt['password'];
30542        $ptParams = json_decode($pt['payment_params'], true);
30543
30544        $formType = $ptParams['formType'];
30545        $currencyCode = $ptParams['currencyCode'];
30546        $paymentPlanId = $ptParams['paymentPlanId'];
30547        $priceId = $ptParams['priceId'];
30548        $paymentType = $ptParams['paymentType'];
30549        $platform = $ptParams['platform'];
30550        $paymentHash = $ptParams['orderCode'];
30551        $afteeTransactionIdentifier = $ptParams['afteeTransactionIdentifier'];
30552
30553        $membershipStatusIndex = UserTable::getStudentMembershipStatus($child->id);
30554        $currencyId = Configure::read('default.settlement_currency_id'); // set currency id to jpy
30555        $cardCompany = Configure::read('card_company.aftee');
30556        $dateTimeNow = date('Y-m-d H:i:s');
30557
30558        $appreciationFlg = 0;
30559        $this->log(__METHOD__ . ' aftee debug --> ' . json_encode($params), $this->logFileName);
30560        $this->log(__METHOD__ . ' aftee debug --> ' . json_encode($pt), $this->logFileName);
30561        $this->log(__METHOD__ . ' aftee debug --> ' . $paymentHash, $this->logFileName);
30562
30563        // set transaction
30564        $dataSource = $this->Payment->getDataSource();
30565        $dataSource->begin();
30566
30567        // initial aftee amount
30568        $totalAmount = (int)$ptParams['paymentAmount'];
30569
30570        if ($totalAmount > 0) {
30571            if (isset($parent->aftee_transaction_identifier) && !empty($parent->aftee_transaction_identifier)) {
30572                $related_id = $parent->aftee_transaction_identifier;
30573            } else {
30574                $related_id = $afteeTransactionIdentifier;
30575            }
30576            
30577            // load PayPal class
30578            if (!class_exists('AfteePaymentService')) {
30579                App::import('Lib', 'AfteePaymentService');
30580            }
30581
30582            $afteeChecksumData = array(
30583                'shopItemId' => "AFTEE" . $formType,
30584                'itemName' => 'FamilyPlanRegistration',
30585                'itemPrice' => $totalAmount,
30586                'itemCount' => 1,
30587                'customerPhoneNumber' => $parent->phone_number,
30588                'customerEmail' => $parent->email,
30589                'shopTransactionNo' => $paymentHash,
30590                'userID' => $parent->id
30591            );
30592            $afteeService = new AfteePaymentService();
30593            $checksum = $afteeService->generateChecksum($afteeChecksumData, false);
30594            
30595
30596            $afteeData = array(
30597                'authentication_token' => $parent->card_token,
30598                'related_id' => $related_id,
30599                'checksum' => $checksum['checksum'],
30600                'shop_transaction_no' => $paymentHash,
30601                'transaction_options' => array(1)
30602            );
30603
30604            $afteePaymentData = array_merge($afteeData, $checksum['settlementData']);
30605
30606            // process Aftee direct payment
30607            $res = $afteeService->directPayment($afteePaymentData);
30608            $checkRes = json_decode($res, true);
30609            $this->log(__METHOD__ . ' aftee --> ' . json_encode($afteePaymentData) . ' --> ' . json_encode($checkRes), $this->logFileName);
30610
30611            if ( isset($checkRes['object']) && $checkRes['object'] == 'transaction') {
30612                $paymentSuccess = true;
30613            } else if ( !array_key_exists("object", $checkRes) || (isset($checkRes['object']) && $checkRes['object'] == 'error')) {
30614                $paymentSuccess = false;
30615            }
30616        } else {
30617            // zero payment
30618            $checkRes = array('aftee zero payment --> family plan registration');
30619            $paymentSuccess = true;
30620        }
30621
30622
30623        if (!$paymentSuccess) {
30624            $this->log(__METHOD__ . ' aftee error --> ' . json_encode($checkRes) . ' --> ' . json_encode($params), $this->logFileName);
30625            return;
30626        }
30627
30628        // payment history data amount
30629        $reservationReceivableAmount = isset($ptParams['reservationReceivableAmount']) ? $ptParams['reservationReceivableAmount'] : 0;
30630        $appreciationReceivableAmount = isset($ptParams['appreciationReceivableAmount']) ? $ptParams['appreciationReceivableAmount'] : 0;
30631        $liveReceivableAmount = isset($ptParams['liveReceivableAmount']) ? $ptParams['liveReceivableAmount'] : 0;
30632
30633        // create payment
30634        $savePaymentArr = array(
30635            'user_id' => $child->id,
30636            'status' => 1,
30637            'reference_id' => $child->id,
30638            'payment_transaction_password' => $ptPassword,
30639            'card_company' => $cardCompany,
30640            'param1' => json_encode($checkRes),
30641            'form_type' => $formType,
30642            'ordd' => $paymentHash,
30643            'transaction_code' => $paymentHash,
30644            'currency_id' => $currencyId,
30645            'currency_code' => $currencyCode,
30646            'payment_id' => $paymentPlanId,
30647            'price_id' => $priceId,
30648            'payment_type' => $paymentType
30649        );
30650
30651        $this->Payment->clear();
30652        $this->Payment->create();
30653        $this->Payment->set($savePaymentArr);
30654        $this->Payment->validate = array();
30655
30656        // update/add user`s settlement amount
30657        $this->User->updateUserPayments($savePaymentArr);
30658
30659        // set payment_id
30660        $paymentSaveID = $this->Payment->id;
30661        $data = array('payment_id' => $paymentSaveID);
30662        $paymentType = Configure::read('payment_types.payment_receivable');
30663
30664        // reservation receivable
30665        if ($reservationReceivableAmount > 0) {
30666            $savePaymentArr = array(
30667                'user_id' => $child->id,
30668                'amount' => $reservationReceivableAmount,
30669                'status' => 1,
30670                'type_id' => 1,
30671                'reference_id' => $child->id,
30672                'card_company' => $cardCompany,
30673                'param1' => json_encode($data),
30674                'form_type' => Configure::read('payment_credit_receivable'),
30675                'ordd' => $paymentHash,
30676                'transaction_code' => $paymentHash,
30677                'currency_id' => $currencyId,
30678                'currency_code' => $currencyCode,
30679                'payment_id' => $paymentPlanId,
30680                'price_id' => $priceId,
30681                'payment_type' => $paymentType
30682            );
30683
30684            // create new payment for reservation receivable
30685            $this->Payment->clear();
30686            $this->Payment->create();
30687            $this->Payment->set($savePaymentArr);
30688            if (!$this->Payment->save()) {
30689                $this->log(__METHOD__ . ' Failed to save payment data for reservation receivable.' . json_encode($savePaymentArr), $this->logFileName);
30690                $dataSource->rollback();
30691                return;
30692            }
30693
30694            // set payment_id
30695            $rrPaymentID = $this->Payment->id;
30696
30697            //update/add user`s settlement amount
30698            $this->User->updateUserPayments($savePaymentArr);
30699
30700            // set payment receivable statuses to 2 - received
30701            $this->PaymentReceivable->updateReceivableReservationPayment(
30702                $child->id,
30703                array(
30704                    'status' => 2,
30705                    'payment_id' => $rrPaymentID,
30706                    'payment_collection_date' => $dateTimeNow,
30707                    'card_company' => $cardCompany,
30708                    'payment_plan_id' => $paymentPlanId,
30709                    'membership_type_index' => $membershipStatusIndex
30710                ),
30711                array(
30712                    'PaymentReceivable.user_id' => $child->id,
30713                    'PaymentReceivable.status' => 0,
30714                    'PaymentReceivable.payment_element_type' => Configure::read('payment_element_type.reservation'),
30715                    'PaymentReceivable.created <=' => $dateTimeNow
30716                )
30717            );
30718        }
30719
30720        // appreciation receivable
30721        if ($appreciationReceivableAmount > 0) {
30722            $savePaymentArr = array(
30723                'user_id' => $child->id,
30724                'amount' => $appreciationReceivableAmount,
30725                'status' => 1,
30726                'type_id' => 1,
30727                'reference_id' => $child->id,
30728                'card_company' => $cardCompany,
30729                'param1' => json_encode($data),
30730                'form_type' => Configure::read('payment_credit_appreciation_receivable'),
30731                'ordd' => $paymentHash,
30732                'transaction_code' => $paymentHash,
30733                'currency_id' => $currencyId,
30734                'currency_code' => $currencyCode,
30735                'payment_id' => $paymentPlanId,
30736                'price_id' => $priceId,
30737                'payment_type' => $paymentType
30738            );
30739
30740            // create new payment for appreciation receivable
30741            $this->Payment->clear();
30742            $this->Payment->create();
30743            $this->Payment->set($savePaymentArr);
30744            if (!$this->Payment->save()) {
30745                $this->log(__METHOD__ . ' Failed to save payment data for appreciation receivable.' . json_encode($savePaymentArr), $this->logFileName);
30746                $dataSource->rollback();
30747                return;
30748            }
30749
30750            // set payment_id
30751            $arPaymentID = $this->Payment->id;
30752
30753            //update/add user`s settlement amount
30754            $this->User->updateUserPayments($savePaymentArr);
30755
30756            // set payment receivable statuses to 2 - received
30757            $this->PaymentReceivable->updateReceivableReservationPayment(
30758                $child->id,
30759                array(
30760                    'status' => 2,
30761                    'payment_id' => $arPaymentID,
30762                    'payment_collection_date' => $dateTimeNow,
30763                    'card_company' => $cardCompany,
30764                    'payment_plan_id' => $paymentPlanId,
30765                    'membership_type_index' => $membershipStatusIndex
30766                ),
30767                array(
30768                    'PaymentReceivable.user_id' => $child->id,
30769                    'PaymentReceivable.status' => 0,
30770                    'PaymentReceivable.payment_element_type' => Configure::read('payment_element_type.appreciation'),
30771                    'PaymentReceivable.created <=' => $dateTimeNow
30772                )
30773            );
30774        }
30775
30776        // live receivable
30777        if ($liveReceivableAmount > 0) {
30778            $savePaymentArr = array(
30779                'user_id' => $child->id,
30780                'amount' => $liveReceivableAmount,
30781                'status' => 1,
30782                'type_id' => 1,
30783                'reference_id' => $child->id,
30784                'card_company' => $cardCompany,
30785                'param1' => json_encode($data),
30786                'form_type' => Configure::read('payment_live_lesson_receivable'),
30787                'ordd' => $paymentHash,
30788                'transaction_code' => $paymentHash,
30789                'currency_id' => $currencyId,
30790                'currency_code' => $currencyCode,
30791                'payment_id' => $paymentPlanId,
30792                'price_id' => $priceId,
30793                'payment_type' => $paymentType
30794            );
30795
30796            // create new payment for live receivable
30797            $this->Payment->clear();
30798            $this->Payment->create();
30799            $this->Payment->set($savePaymentArr);
30800            if (!$this->Payment->save()) {
30801                $this->log(__METHOD__ . ' Failed to save payment data for live receivable.' . json_encode($savePaymentArr), $this->logFileName);
30802                $dataSource->rollback();
30803                return;
30804            }
30805
30806            // set payment_id
30807            $lrPaymentID = $this->Payment->id;
30808
30809            //update/add user`s settlement amount
30810            $this->User->updateUserPayments($savePaymentArr);
30811
30812            // set payment receivable statuses to 2 - received
30813            $this->PaymentReceivable->updateReceivableReservationPayment(
30814                $child->id,
30815                array(
30816                    'status' => 2,
30817                    'payment_id' => $lrPaymentID,
30818                    'payment_collection_date' => $dateTimeNow,
30819                    'card_company' => $cardCompany,
30820                    'payment_plan_id' => $paymentPlanId,
30821                    'membership_type_index' => $membershipStatusIndex
30822                ),
30823                array(
30824                    'PaymentReceivable.user_id' => $child->id,
30825                    'PaymentReceivable.status' => 0,
30826                    'PaymentReceivable.payment_element_type' => Configure::read('payment_element_type.live'),
30827                    'PaymentReceivable.created <=' => $dateTimeNow
30828                )
30829            );
30830        }
30831
30832        $dataSource->commit();
30833        $fields = array('status' => 1);
30834        if (isset($checkRes)) {
30835            $fields['response_text'] = array('aftee' => $checkRes);
30836        }
30837
30838        // update payment transaction
30839        $this->PaymentTransaction->updateWPPaymentTransaction(array('id' => $ptId, 'fields' => $fields));
30840
30841        return 'success_order';
30842    }
30843    /**
30844     * @api {get} /mobapp/payment/credit_retry_complete/:token mobapp_credit_retry_complete()
30845     * @apiName mobapp_credit_retry_complete
30846     * @apiGroup Payment
30847     * @apiDescription This endpoint is used to complete the credit card retry process.
30848     * 
30849     * @apiParam {String} token User token.
30850     * 
30851     * @apiSuccess {View} Redirect Redirects to {{ENV}}/mobapp/close
30852     * 
30853     * @apiError {View} Redirect Redirects to {{ENV}}/mobapp/retrypage if user token / user does not exist.
30854     * 
30855     * @apiSuccessExample Success Response:
30856     * Redirects to {{ENV}}/mobapp/close
30857     * 
30858     * @apiErrorExample Error Response:
30859     * Redirects to {{ENV}}/mobapp/retrypage
30860     * 
30861     * @apiSampleRequest off 
30862     */
30863    public function mobapp_credit_retry_complete(){
30864        $apiToken = !empty($this->request->query['token']) ? $this->request->query['token'] : null;
30865        $userParams = $this->request->query; // NJ-69126 ~ [Warning] Undefined variable $userParams
30866        //- validate user token
30867        if (!$apiToken) {
30868            $this->log(__METHOD__ . ' User token does not exist. ' . json_encode($userParams), 'card_retry');
30869            return myTools::getUrl() . '/mobapp/retrypage' . myTools::getMobappToken($_GET);            
30870        }
30871
30872        $userData = $this->User->getUserDataByApiToken($apiToken);
30873        //- validate user data
30874        if (!$userData) {
30875            $this->log(__METHOD__ . ' User does not exist. ' . json_encode($userParams), 'card_retry');
30876            return myTools::getUrl() . '/mobapp/retrypage' . myTools::getMobappToken($_GET);
30877        }
30878        
30879        $userData = $userData['User'];
30880
30881        // ~ process child receivable
30882        $childsDetail = $this->User->getChildsDetail($userData['id']);
30883
30884        if (!empty($childsDetail)) {
30885            foreach ($childsDetail as $detail) {
30886                $this->processChildReceivablePayment($detail['User'], $userData);
30887            }
30888        }
30889
30890        return $this->redirect(myTools::getUrl() . '/mobapp/close'.  myTools::getMobappToken($_GET));
30891    }
30892
30893    private function setLitePaymentInfoView($user = array(),$pcFlg = false,$isFreeOrTempUser = false,$compPageAllow = null){
30894
30895        if (!$user) {
30896            return false;
30897        }
30898
30899        // - init var 
30900        $currencyCode = $user['currency_code'];
30901
30902        $litePlanDataDisplay = array(
30903            'amount' => 0,
30904            'amountConstTaxDeducted' => 0,
30905            'priceId' => null
30906        );
30907
30908        $priceId = null;
30909
30910        $checkLitePlanSupported = $this->checkLitePlanSupported($user,$pcFlg,$compPageAllow);
30911
30912        if (isset($checkLitePlanSupported['enableLitePlan']) && $checkLitePlanSupported['enableLitePlan']) {
30913            // fetch light plan description
30914            $litePlanDataDisplay = $this->PaymentPlanPrice->getPaymentData(array(
30915                'currencyCode' => $currencyCode,
30916                'paymentPlanId' => Configure::read('payment_plans.light_plan'),
30917                'logFileName' => 'card_reregister'
30918            ));
30919
30920            // - set price id 
30921            $priceId = $litePlanDataDisplay['priceId'];
30922
30923            // - set price id for lite plan free
30924            if ($isFreeOrTempUser) {
30925                # get lite free data 
30926                $freeTrialData = $this->PaymentPlanPrice->getPaymentData(array(
30927                    'currencyCode' => $user['currency_code'],
30928                    'paymentPlanId' => Configure::read('payment_plans.light_plan_free'),
30929                    'logFileName' => 'card_reregister'
30930                ));
30931
30932                $priceId = $freeTrialData['priceId'];
30933            }
30934
30935            // - set price id 
30936            $litePlanDataDisplay['priceId'] = $priceId;
30937        }
30938
30939        // - check if enabled lite plan 
30940        $enableLitePlan = isset($checkLitePlanSupported['enableLitePlan']) ? $checkLitePlanSupported['enableLitePlan'] : 0;
30941    
30942        $this->set('liteMonthlyPrice', myTools::formatAmount($litePlanDataDisplay['amount']));
30943        $this->set('litePlanAmount',$litePlanDataDisplay['amount']);
30944        $this->set('liteMonthylyPriceNoTax', myTools::formatAmount($litePlanDataDisplay['amountConstTaxDeducted']));
30945        $this->set('liteMonthylyPriceID', $priceId); //lite plan free price id
30946        $this->set('enableLitePlan',$enableLitePlan);
30947    }
30948
30949    public function liteUserAddCoinRewardForReenroll($user = array()){
30950        $this->autoRender = false;
30951
30952        $id = isset($user['id']) ? $user['id'] : null;
30953
30954
30955        if (!$id) {
30956            return false;
30957        }
30958
30959    
30960        // - fetch users mc coins
30961        $_monthlyPoints = $this->UsersPoint->getCurrentUserMCPoint($id); //  mc coins
30962
30963        // - fetch user current memo
30964        $updateMemo ="";
30965        $this->User->clear();
30966        $currentuser = $this->User->find('first',array(
30967            'conditions' => array(
30968                'User.id' => $id
30969            ),
30970            'recursive' => -1
30971        ));
30972        $currentUserMemo = $currentuser['User']['memo'];
30973        $dateNow = date('Y-m-d H:i:s');
30974
30975        // - confiscating mc coin
30976        if ((int) $_monthlyPoints > 0) {
30977            $_confiscateParams = array(
30978                'userId' => $id,
30979                'point' => $_monthlyPoints,
30980                'kbn' => 18, // Administrator Change/Minus
30981                'coinType' => 3
30982            );
30983
30984            $confiscate = $this->UsersPoint->confiscateUserLitePoints($_confiscateParams);
30985        
30986            if ($confiscate) {
30987                $updateMemo = $updateMemo . "\n {$dateNow} (Previous Coins (MC)【Confiscated】 : {$_monthlyPoints}. )";
30988            }
30989        }
30990
30991        $_doneConfiscatePoints = ClassRegistry::init('UsersPointHistory')->confiscateUserLitePointsCoinBox($id);
30992
30993    
30994        $nextChargeDate = $this->User->getNextChargeDate();
30995
30996        // - set to add monthly coin
30997        $_pointParams = array(
30998            'userId' => $id,
30999            'point' => Configure::read('lite_plan_monthly_coin'),
31000            'kbn' => Configure::read('lite_plan_bonus_kbn'), // 
31001            'kbnType' => 1, // add coin
31002            'coinType' => 3, // mc coin
31003            'dateExpiration' => $nextChargeDate,
31004            'coinFailMessage' => Configure::read('coin.failed.membership')
31005        );
31006
31007    
31008        // add user's points 
31009        $givebonus = $this->UsersPoint->performPointTransaction($_pointParams);
31010
31011    
31012        if ($givebonus) {
31013            $_coins = Configure::read('lite_plan_monthly_coin');
31014            $updateMemo = $updateMemo . "\n {$dateNow} Light Plan Bonus Coins (MC): {$_coins}";
31015        }
31016
31017        if (!empty($updateMemo)) {
31018            $updateMemo = $updateMemo . "\n" . $currentUserMemo;
31019            // - update user memo
31020            $this->User->clear();
31021            $this->User->set( array('id' => $id,'memo' => $updateMemo));
31022            $this->User->save();
31023        }
31024        
31025    }
31026
31027    public function processChangePlan(){
31028        $this->autoRender = false;
31029        $this->layout = false;
31030
31031        $this->response->disableCache();
31032
31033        $result = false;
31034        $error = true;
31035
31036        if ($this->request->is('post')) {
31037            $data = $this->request->data;
31038            $userID = $data['user_id'];
31039            $formType = $data['form_type'];
31040
31041            if (UserTable::checkPayingUser($userID)) {
31042                return json_encode(array('error' => true));
31043            }
31044
31045            // - if already has memcache on process 
31046            $checkProcess = $this->memcache->get('process_change_plan_'.$userID);
31047
31048            if ($checkProcess) {
31049                $this->memcache->delete('process_change_plan_'.$userID);
31050                return json_encode(array('hard_refresh' => true));
31051            }
31052
31053            $this->memcache->set(array(
31054                'key' => 'process_change_plan_'.$userID,
31055                'value' => $userID,
31056                'expire' => 3600 // 1 hour
31057            ));
31058
31059            if (!$userID || !$formType || !isset($data['payment_plan_type'])) {
31060                return json_encode(array('error' => true));
31061            }
31062
31063            // -- check if user exist 
31064            $user = $this->User->find('first',array(
31065                'conditions' => array(
31066                    'User.id' => $userID
31067                ),
31068                'recursive' => -1
31069            ));
31070
31071            if (!$user) {
31072                return json_encode(array('error' => true));
31073            }
31074
31075            // - validate user plan
31076            if(
31077                isset($user['User']['payment_plan_id']) && 
31078                $user['User']['payment_plan_id'] == 1 &&
31079                $data['payment_plan_type'] == 0 // selected plan type
31080            ) {
31081                return json_encode(array('error' => true));
31082            }
31083
31084            $user = $user['User'];
31085            $planID = $plan_before  = $user['payment_plan_id'];
31086            $paymentPlanType = $data['payment_plan_type'];
31087            $isFreeTrialNot = ($planID == Configure::read('payment_plans.free_trial')) ? true : false;
31088            $isLiteplanFree = ($planID == Configure::read('payment_plans.light_plan_free')) ? true : false;
31089            $plan_after = "";
31090
31091            $removeAllHeldCoins = false;
31092            $removeAllHeldCoupon = false;
31093            $offUnlimitedOptionNative = false;
31094            $offUnlimitedOptionCallan = false;
31095            $giveLiteMonthlyCoin = false;
31096            $removeLiteBonusCoin = true;
31097            $amount = 0;
31098
31099            $isPlanDownGrade = false;
31100            $planFormType = Configure::read('payment_lite_plan_upgrade');
31101
31102            $membershipTypes = UserTable::getEngMembershipTypeData();
31103            $userObject = new UserTable($user);
31104
31105            $membershipTypeIndex = $userObject->getMembershipTypeIndex();
31106            $statusBefore = $membershipTypes[$membershipTypeIndex];
31107            $statusAfter = $membershipTypes[1];
31108
31109            $totalPayment = 0;
31110            $chargePaymentFlg = false;
31111            
31112        
31113            // - check if from free trial user not yet conducted and change the plan to lite plan
31114            if ($isFreeTrialNot && (int) $paymentPlanType == 1) {
31115                $removeAllHeldCoins = true;
31116                $removeAllHeldCoupon = true;
31117                $offUnlimitedOptionNative = true;
31118                $offUnlimitedOptionCallan = true;
31119                $giveLiteMonthlyCoin = true;
31120
31121                // - set the lite plan id to paid
31122                $planID = $plan_after = Configure::read('payment_plans.light_plan');
31123                $planFormType = Configure::read('payment_lite_plan_downgrade');
31124
31125                // - set status after 
31126                $_mt = Configure::read('membership_type_lightplan_paid');
31127                $statusAfter = $membershipTypes[$_mt];
31128
31129                $chargePaymentFlg = true;
31130            }
31131
31132            // - changes from ligth plan free to (premium plan paid or premium plan paid with annual discount option)
31133            if ($isLiteplanFree && (int) ($paymentPlanType == 0 || $paymentPlanType == 2)) {
31134
31135                // - set premium plan id 
31136                $planID = $plan_after = Configure::read('payment_plans.premium_plan');
31137                $planFormType = Configure::read('payment_lite_plan_upgrade');
31138
31139                // - set status after to premium plan (paid)
31140                $_mt = Configure::read('membership_type_premiumplan_paid');
31141                $statusAfter = $membershipTypes[$_mt];
31142
31143                $chargePaymentFlg = true;
31144            }
31145
31146            // - changes plan from premium plan (paid) -> light plan (paid)
31147            if (!$isFreeTrialNot && (int) $paymentPlanType == 1) {
31148                $chargePaymentFlg = true;
31149
31150                $removeAllHeldCoins = true;
31151                $removeAllHeldCoupon = true;
31152                $offUnlimitedOptionNative = true;
31153                $offUnlimitedOptionCallan = true;
31154                $giveLiteMonthlyCoin = true;
31155
31156                // - set the lite plan id to paid
31157                $planID = $plan_after = Configure::read('payment_plans.light_plan');
31158                $planFormType = Configure::read('payment_lite_plan_downgrade');
31159
31160                // - set status after 
31161                $_mt = Configure::read('membership_type_lightplan_paid');
31162                $statusAfter = $membershipTypes[$_mt];
31163
31164                $chargePaymentFlg = true;
31165            }
31166
31167            // - changes the plan from light plan (paid) -> (premium plan paid (paid) or premium plan paid with annual discount option)
31168            if (!$isLiteplanFree && (int) ($paymentPlanType == 0 || $paymentPlanType == 2)) {
31169                $removeAllHeldCoins = true;
31170                $removeAllHeldCoupon = true;
31171                $chargePaymentFlg = true;
31172
31173                $offUnlimitedOptionNative = true;
31174                $offUnlimitedOptionCallan = true;
31175
31176                // - set premium plan id 
31177                $planID = $plan_after = Configure::read('payment_plans.premium_plan');
31178                $planFormType = Configure::read('payment_lite_plan_upgrade');
31179
31180                // - set status after to premium plan (paid)
31181                $_mt = Configure::read('membership_type_premiumplan_paid');
31182                $statusAfter = $membershipTypes[$_mt];
31183            }
31184
31185            //- NJ-27262 Chocotto Camp(Paid)
31186            if ($paymentPlanType == Configure::read('register_plan_types.chocotto')) {
31187                $removeAllHeldCoins = true;
31188                $chargePaymentFlg = true;
31189
31190                $offUnlimitedOptionNative = true;
31191                $offUnlimitedOptionCallan = true;
31192
31193                // - set chocotto plan id 
31194                $planID = $plan_after = Configure::read('payment_plans.chocotto_plan');
31195                $planFormType = Configure::read('payment_credit_chocotto_monthly_payment');
31196
31197                // - set status after to chocotto plan (paid)
31198                $_mt = Configure::read('membership_type_chocotto_plan_paid');
31199                $statusAfter = $membershipTypes[Configure::read('membership_type_chocotto_plan_paid')];
31200                //NJ-33743
31201                $memcached = new myMemcached();
31202                $memcached->set(array(
31203                    'key'    => 'user_plan_change_premium_to_chocotto',
31204                    'value'  => true,
31205                    'expire' => 120
31206                ));
31207            }
31208
31209            $plan = $this->PaymentPlanPrice->getPaymentData(array(
31210                'currencyCode' => $user['currency_code'],
31211                'paymentPlanId' => $planID,
31212                'logFileName' => 'card_reregister'
31213            ));
31214
31215            #processPayPalPayment
31216            if (!$plan) {
31217                return json_encode(array('error' => true));
31218            }
31219
31220            // - validate to double check if the plan that the user want's
31221            if ((int) $planID == (int) $plan_before) {
31222                # check if user is already changed into plan
31223                return json_encode(array('hard_refresh' => true));
31224            }
31225
31226            $removeAllHeldCoins = true; // override to remove all mc coins
31227
31228            $paramsData = array(
31229                'removeAllHeldCoins' => $removeAllHeldCoins,
31230                'removeAllHeldCoupon' => $removeAllHeldCoupon,
31231                'offUnlimitedOptionNative' => $offUnlimitedOptionNative,
31232                'offUnlimitedOptionCallan' => $offUnlimitedOptionCallan,
31233                'giveLiteMonthlyCoin' => $giveLiteMonthlyCoin,
31234                'amount' => $amount,
31235                'paymentPlanData' => $plan,
31236                'formType' => $planFormType,
31237                'statusAfter' => $statusAfter,
31238                'statusBefore' => $statusBefore,
31239                'removeLiteBonusCoin' => $removeLiteBonusCoin,
31240                'totalPayment' => $totalPayment
31241            );
31242
31243            if ($chargePaymentFlg) {
31244                $totalPayment  = $plan['amount'];
31245                
31246                // get reserve payment receivable
31247                $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userID);
31248
31249                // get live lesson payment receivable
31250                $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userID, false, Configure::read('appreciation_data.payment_element_type'));
31251
31252                // get live lesson payment receivable
31253                $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userID, false, Configure::read('payment_element_type.live'));
31254
31255                // - native option payment ??
31256                $totalPayment =  $totalPayment + $receivablePayment + $appreciationReceivable + $liveLessonReceivable; 
31257
31258                if ($paymentPlanType == 2) {
31259                    // get active annual discount option
31260                    $annualDiscountOptionData = $this->DiscountOptionsPrice->getPaymentData(['currencyCode' => $user['currency_code'], 'discountOptionId' => Configure::read('discount_option.annual.plan_id')]);
31261
31262                    if (!$annualDiscountOptionData) {
31263                        return json_encode(array('hard_refresh' => true));
31264                    }
31265
31266                    $annualDiscountOptionData += [
31267                        'dosh_event' => Configure::read('discount_option.dosh_event.annual_discount'),
31268                        'dosh_status' => Configure::read('discount_option.dosh_status.monthly_discount')
31269                    ];
31270
31271                    $paramsData['discountOption'] = $annualDiscountOptionData;
31272                    $totalPayment = $totalPayment - $annualDiscountOptionData['amount'];
31273                }
31274
31275                $paramsData['totalPayment'] = $totalPayment;// - set to charge
31276
31277            }
31278
31279            $paramsData['charge_payment_flg'] = $chargePaymentFlg;
31280            $paramsData['raw_monthly_amount'] = $plan['amount'];
31281    
31282            // - if paypal user 
31283            if ((int) $user['card_company'] == Configure::read('card_company.paypal')) {
31284                $result = $this->paypal_payment_change_plan_process($paramsData,$user);
31285                $this->log(__METHOD__ . ' here on starting the paypal process paramsData | '.json_encode($paramsData), 'paypal_debug');
31286            }
31287
31288            if ((int) $user['card_company'] == Configure::read('card_company.zeus')) {
31289                $result = $this->zeus_payment_change_plan($paramsData,$user);
31290            }
31291
31292            $error = ($result['success']) ? false : true;
31293
31294            // - update ? 
31295            if ($result) {
31296                $this->User->clear();
31297                $read = $this->User->read(array('id','payment_plan_id','price_id'),$userID);
31298
31299                if ($read) {
31300                    $this->sharedUserData['User']['payment_plan_id'] = $read['User']['payment_plan_id'];
31301                    $this->sharedUserData['User']['price_id'] = $read['User']['price_id'];
31302                }
31303
31304                $membership = $userObject->getMembershipTypeIndex();
31305                if (in_array($membership, Configure::read('allow_coupon.membership_type_free'))) {
31306                    $ruData = array(
31307                        'referee_id' => $userID,
31308                        'payment_plan_id' => Configure::read('payment_plans.premium_plan'),
31309                        'currency_code' => $user['currency_code'],
31310                        'form_type' => Configure::read('payment_credit_authentication'),
31311                        'logFileName' => 'card_reregister'
31312                    );
31313
31314                    $couponReferredData = $this->UsersReferral->checkReferredUser($ruData);
31315                    if (isset($couponReferredData['error']) && $couponReferredData['error']) {
31316                        $this->log(__METHOD__ . ' Failed to update users referral event flg.' . json_encode($ruData), 'card_reregister');
31317                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userID, 'Failed to update users referral event flg.', $ruData);
31318                    }
31319                }
31320
31321
31322                if (in_array($membership, Configure::read('allow_coupon.membership_type'))) {
31323                    $params = array(
31324                        'userId' => $userID,
31325                        'action_type' => 1 // confiscate only the used status 
31326                    );
31327                    if (!$this->UsersCouponV1->confiscateAllCoupon($params)) {
31328                        $this->log(__METHOD__ . ' Failed to conficate change plan.' . json_encode($userID), 'card_reregister');
31329                    }
31330                }
31331            }
31332
31333            if (
31334                isset($result['success']) && 
31335                $result['success'] &&
31336                $this->User->isParent($userID) // - check if parent user
31337            ) {
31338                $this->processChildWithdrawal($user);
31339            }
31340
31341            // delete memcache
31342            if ($this->memcache->get('process_change_plan_'.$userID)) {
31343                $this->memcache->delete('process_change_plan_'.$userID);
31344            }
31345
31346            //- logout user chocotto plan
31347            if (
31348                isset($result['success']) && 
31349                $result['success'] &&                
31350                $paymentPlanType == Configure::read('register_plan_types.chocotto')
31351            ) {
31352
31353                //- add default daily lesson time, if no data yet on
31354                $this->UsersDetail->chocottoCampUserDetails($userID, true);
31355                $this->Auth->logout();
31356            }
31357
31358            return json_encode(array(
31359                'success' => $result['success'],
31360                'error' => $error,
31361                'paymentHash' => $result['paymentHash']
31362            ));
31363        }
31364
31365        return json_encode(array(
31366            'success' => $result['success'],
31367            'error' => $error,
31368            'paymentHash' => $result['paymentHash']
31369        ));
31370    }
31371
31372    private function processChildWithdrawal($userData = array()) {
31373
31374        if(!isset($userData['id']) || !$userData['id']) {
31375            return false;
31376        }
31377
31378        $user = new UserTable($userData);
31379        $user_id = $user->id;
31380
31381        $childData = array();
31382        $wd = date('Y/m/d H:i:s');
31383
31384        // - get children data
31385        $childsDetail = $this->User->getChildsDetail($user_id);
31386
31387        $lastModifiedDate = date('YmdHis');
31388
31389        $childDataUpdateNativeOption = array();
31390        $childDataUpdateCallanOption = array();
31391
31392        // - check children data if any
31393        if (!empty($childsDetail)) {
31394
31395            $saveLogParams['doubleCheckFlg'] = 2; // unsubscribed
31396
31397            foreach ($childsDetail as $detail) {
31398
31399                // - db object
31400                $db = ConnectionManager::getDataSource('default');
31401                if ($db->isConnected()) {
31402                    $db->close(); // stop
31403                }
31404                $db->reconnect();
31405
31406                // - update child memo
31407                $childMemo = $wd.' system-pc 退会 : parent ['. $user_id .'] change plan' ."\n".$detail['User']['memo'];
31408
31409                //default 
31410                $childNativeOptionParams = array();
31411
31412                $childUpdateParam = array(
31413                        'id' => $detail['User']['id'],
31414                        'deactivation_time' => $lastModifiedDate,
31415                        'fail_flg' => 0,
31416                        'charge_flg' => 0,
31417                        'double_check_flg' => 2,
31418                        'native_option' => 0,
31419                        'callan_option' => 0,
31420                        'memo' => $childMemo,
31421                        'parent_id' => NULL, 
31422                        'next_charge_date' => NULL, 
31423                        'monthly_payment' => null, 
31424                        'price_id' => null,
31425                        'payment_plan_id' => null,
31426                        'card_token' => null,
31427                        'card_company' => null,
31428                        'expired_card_flg' => 0,
31429                        'card_expiration_date' => null,
31430                        'card_number' => null,
31431                        'card_brand' => null,
31432                        'aftee_transaction_identifier' => null,
31433                        'wp_transaction_identifier' => null,
31434                        'google_cloud_id' => null
31435                );
31436
31437                if ($userData['card_company'] == Configure::read('card_company.aftee')) {
31438                    $childUpdateParam['card_company'] = NULL;
31439                    $childUpdateParam['card_brand'] = 'AFTEE2';
31440                }
31441
31442                // - check if has native option
31443                if (isset($detail['User']['native_option']) && $detail['User']['native_option']) {
31444
31445                        $childNativeOptionParams = array(
31446                            'id' => $detail['User']['id'],
31447                            'native_option_cancellation_time' => date("Y-m-d H:i:s")
31448                        );
31449
31450                        $childDataUpdateNativeOption[] = array('User' => $childNativeOptionParams);
31451                }
31452
31453                // - check if has callan option
31454                if (isset($detail['User']['callan_option']) && $detail['User']['callan_option']) {
31455                        $childCallanOptionParams = array(
31456                            'id' => $detail['User']['id'],
31457                            'callan_option_cancellation_time' => date("Y-m-d H:i:s")
31458                        );
31459
31460                        $childDataUpdateCallanOption[] = array('User' => $childCallanOptionParams);
31461                }
31462
31463                // - set update data from each child
31464                $childData[] = array('User' => $childUpdateParam);
31465
31466                // - add deactivation log
31467                $this->loadModel('FamilyDeactivationLog');
31468                $this->FamilyDeactivationLog->addLog($detail['User']['id']);
31469
31470                // - disable child's reserved lessons
31471                $this->LessonSchedule->deactivateDisableReservedLessons($detail['User']['id'], true);
31472
31473                // save child change membership status
31474                $saveLogParams['userData'] = $detail;
31475                UserStatusChangeLogTable::saveLogUnsubscribeUser($saveLogParams);
31476                
31477                $switchAccountParams = array(
31478                    'parentId' => $user_id,
31479                    'userId' => $detail['User']['id']
31480                );
31481
31482                // - delete switch account data for child
31483                $this->UsersFamilyAccount->removeSwitchAccount($switchAccountParams);
31484
31485                // - add deactivation lock
31486                $user->saveUserDeactivationLock($detail['User']['id']);
31487
31488            }
31489
31490            $this->User->saveMany($childData);
31491
31492            if (isset($childDataUpdateNativeOption) && $childDataUpdateNativeOption) {
31493                // - update the native option
31494                $this->User->saveMany($childDataUpdateNativeOption);
31495            }
31496
31497            if (isset($childDataUpdateCallanOption) && $childDataUpdateCallanOption) {
31498                // - update the callan option
31499                $this->User->saveMany($childDataUpdateCallanOption);
31500            }
31501
31502            // - delete from family plan list
31503            $this->FamilyPlanList->deleteAll(array('FamilyPlanList.parent_id' => $user_id));
31504
31505            return true;
31506        }
31507    }
31508
31509    private function paypal_payment_change_plan_process($data = array(),$user = array()){
31510
31511        $logFileName = 'paypal_debug';
31512
31513        // load PayPal class
31514        if (!class_exists('PayPal')) {
31515            App::import('Lib', 'PayPal');
31516        }
31517
31518        $paypal = new PayPal();
31519
31520        $result = ['success' => false, 'paymentHash' => null];
31521
31522        // get access token data
31523        $accessTokenData = $paypal->getAccessToken();
31524
31525        if (!isset($accessTokenData['access_token'])) {
31526            $this->log(__METHOD__ . " Error. --> " . json_encode($accessTokenData), $logFileName);
31527            return $result;
31528        }
31529
31530        // - set access token data
31531        $accessToken = $accessTokenData['access_token'];
31532
31533        if (!$user || !$data) {
31534            $this->log(__METHOD__ . ' Missing billing agreement param(s). --> ' . json_encode($user), $logFileName);
31535            return $result;
31536        }
31537
31538        $formType = $data['formType'] ?? null;
31539
31540        if (!$formType) {
31541            $this->log(__METHOD__ . ' Missing form type param(s). --> ' . json_encode($data), $logFileName);
31542            return $result;
31543        }
31544
31545        if (!$data['statusAfter']) {
31546            $this->log(__METHOD__ . ' Missing statusAfter param(s). --> ' . json_encode($data), $logFileName);
31547            return $result;
31548        }
31549
31550        if (!isset($data['charge_payment_flg'])) {
31551            $this->log(__METHOD__ . ' Missing charge_payment_flg param(s). --> ' . json_encode($data), $logFileName);
31552            return $result;
31553        }
31554
31555        // - set total amount 
31556        $totalPayment = $nativeOptionPayment = $callanOptionPayment = $discountedAmount = 0;
31557
31558        $totalPayment = $data['totalPayment'] ?? 0;
31559        $monthlyPayment = $data['raw_monthly_amount'] ?? 0;
31560
31561        // - update user for creating payment transaction
31562        $user['payment_plan_id'] = $paymentPlanId = $data['paymentPlanData']['paymentPlanId'];
31563        $user['price_id'] = $priceId = $data['paymentPlanData']['priceId'];
31564        $user['paymentAmount'] = $totalPayment;
31565
31566        $paymentType = Configure::read('payment_types.payment_plan');
31567        $cardCompany = Configure::read('card_company.paypal');
31568
31569        $familyId = null;
31570        $billingAgreementId = $user['paypal_billing_agreement_id'];
31571        $platform = $user['platform'];
31572
31573        $statusBefore = $data['statusBefore'];
31574        $userId = $user['id'];
31575        $sendId = $userId;
31576
31577        $paymentParams = array(
31578            'currencyCode' => $user['currency_code'],
31579            'formType' => $formType,
31580            'paymentType' => $paymentType,
31581            'logFileName' => $logFileName,
31582            'paymentAmount' => $totalPayment,
31583            'familyId' => $familyId,
31584            'priceId' => $priceId,
31585            'paymentPlanId' => $paymentPlanId,
31586            'nativeOptionPayment' => $nativeOptionPayment,
31587            'callanOptionPayment' => $callanOptionPayment,
31588            'statusBefore' => $statusBefore,
31589            'statusAfter' => $data['statusAfter'],
31590            'platform' => $platform
31591        );
31592
31593        if (isset($data['discountOption'])) {
31594            $paymentParams['discountOption'] = $data['discountOption'];
31595            $monthlyPayment -= $data['discountOption']['amount'];
31596            $paymentParams['discountOption'] += [
31597                'dosh_type' => Configure::read('discount_option.dosh_type.plan_change'),
31598                'dosh_status' => Configure::read('discount_option.dosh_status.subscription'),
31599                'option_after_name' => 'Annual Discount Option',
31600                'option_type' => 3
31601            ];
31602        }
31603
31604        $paymentHash = myTools::generateOrderCode($userId);
31605        $result['paymentHash'] = $paymentHash;
31606
31607        $ptParams = array(
31608            'user_id' => $userId,
31609            'payment_hash' => $paymentHash,
31610            'payment_params' => json_encode($paymentParams),
31611            'course_id' => Configure::read("credit.course_id")
31612        );
31613
31614        // create payment transaction
31615        if (!$pt = $this->PaymentTransaction->setWPPaymentTransaction($ptParams)) {
31616            $this->log(__METHOD__ . ' Failed to create payment transaction. --> ' . json_encode($ptParams), $logFileName);
31617            return $result;
31618        }
31619
31620        // set transaction
31621        $dataSource = $this->User->getDataSource();
31622        $dataSource->begin();
31623
31624        $dateNow = date('Y-m-d H:i:s');
31625        $mpptId = $pt['id']; // transaction id
31626        $currencyId = Configure::read('default.settlement_currency_id'); // set currency id to jpy
31627        $currencyCode = $user['currency_code'];
31628
31629        $paymentHash = $pt['payment_hash'];
31630        $ptPassword = $pt['password'];
31631
31632        $createOrderParams = array(
31633            'accessToken' => $accessToken,
31634            'paypalRequestId' => $pt['id'],
31635            'intent' => 'CAPTURE',
31636            'paymentHash' => $paymentHash,
31637            'userId' => $sendId,
31638            'currencyCode' => $currencyCode,
31639            'amount' => (int)$totalPayment,
31640            'billingAgreementId' => $billingAgreementId
31641        );
31642
31643        $paypalData = $createOrderParams;
31644        $this->log(__METHOD__ . ' totalPayment | '.json_encode($totalPayment), 'paypal_debug');
31645
31646        // - if from free trial
31647        if ($totalPayment == 0) {
31648            $createOrderParams['amount'] = 1;
31649        }
31650
31651        // create order
31652        $createOrderResult = $paypal->createOrder($createOrderParams);
31653        $paypalData['create_order_data'] = $createOrderResult;
31654
31655        // save settlement history for tracking
31656        if (
31657            !SettlementHistoryTable::add(array(
31658                    'userId' => $userId,
31659                    'params' => json_encode($paypalData),
31660                    'createdIp' => $dateNow,
31661                    'modifiedIp' => $dateNow
31662                )
31663            ) 
31664        ) {
31665            $this->log(__METHOD__ . ' Failed to save paypal result data in settlement history. ' . json_encode($paypalData), $logFileName);
31666            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save paypal result data in settlement history', $paypalData);
31667            return $result;
31668        }
31669
31670        if (isset($createOrderResult['status']) && $createOrderResult['status'] === 'COMPLETED'){
31671
31672            $paymentData = array(
31673                'user_id' => $userId,
31674                'amount' => $monthlyPayment,
31675                'status' => 1,
31676                'reference_id' => $userId,
31677                'payment_transaction_password' => $ptPassword,
31678                'card_company' => $cardCompany,
31679                'param1' => json_encode($paypalData),
31680                'form_type' => $formType,
31681                'ordd' => $paymentHash,
31682                'transaction_code' => $paymentHash,
31683                'currency_id' => $currencyId,
31684                'currency_code' => $currencyCode,
31685                'payment_id' => $paymentPlanId,
31686                'price_id' => $priceId,
31687                'payment_type' => $paymentType,
31688                'discounted_amount' => $discountedAmount
31689            );
31690
31691            // create new payment
31692            $this->Payment->clear();
31693            $this->Payment->create();
31694            $this->Payment->set($paymentData);
31695            $this->Payment->validate = array();
31696
31697            // check if payment was not saved
31698            if (!$this->Payment->save()) {
31699                $this->log(__METHOD__ . ' Failed to save payment data. ' . json_encode($paymentData) . ' -- ' . json_encode($data), $logFileName);
31700                return $result;
31701            }
31702
31703            // check if payment plan upgrade
31704            if ($formType == Configure::read('payment_lite_plan_upgrade')) {
31705                // get user zero student discount term
31706                $discountOptionTermData = $this->UserDiscountOptionsTerm->getTerm([
31707                    'user_id' =>  $userId,
31708                    'discount_option_id' => Configure::read('discount_option.zero_student.plan_id'),
31709                    'status' => 1
31710                ]);
31711
31712                // stop zero student discount
31713                if ($discountOptionTermData) {
31714                    // open tunnel
31715                    myTools::initializeApiTunnel(['DiscountOptionController']);
31716
31717                    // initialize controller
31718                    $doc = new DiscountOptionController(); 
31719
31720                    $docParams = [
31721                        'discountOptionId' => $discountOptionTermData['discount_option_id'],
31722                        'discountOptionPriceId' => $discountOptionTermData['discount_option_price_id'],
31723                        'termId' => $discountOptionTermData['discount_option_term_id'],
31724                        'cancellationFee' => 0,
31725                        'cancellationType' => Configure::read('discount_option.dosh_type.plan_change'),
31726                        'userData' => $user,
31727                        'fromController' => $this->request->params['controller'],
31728                        'fromAction' => $this->request->params['action'],
31729                        'doshStatus' => Configure::read('discount_option.dosh_status.midterm_cancellation')
31730                    ];
31731
31732                    // set data
31733                    $doc->params = $docParams;
31734
31735                    if (!$doc->stopDiscountOption()) {
31736                        $this->log(__METHOD__ . ' Failed to stop discount option. ' . json_encode($docParams) . ' -- ' . json_encode($data), $logFileName);
31737                        return $result;
31738                    }
31739                }
31740            }
31741
31742            $paymentId = $this->Payment->id;
31743            //update/add user`s settlement amount
31744            $this->User->updateUserPayments($paymentData);
31745
31746
31747            $baId = $billingAgreementId;
31748
31749            $saveUserArr = array(
31750                'id' => $userId,
31751                'status' => 1,
31752                'modified' => $dateNow,
31753                'fail_flg' => 0,
31754                'charge_flg' => 1,
31755                'counseling_attended_flg' => 0,
31756                'card_company' => $cardCompany,
31757                'hash16' => $userId,
31758                'payment_plan_id' => $paymentPlanId,
31759                'price_id' => $priceId,
31760                'corporate_id' => null,
31761                'corporate_type' => null,
31762                'last_charge_date' => $dateNow
31763            );
31764
31765            // - check charge flag to change the last and next charge date
31766            $chargeFlg = isset($data['charge_payment_flg']) ? (int) $data['charge_payment_flg'] : 0;
31767            $liteNxtChargeDate = null;
31768            if ($chargeFlg) {
31769            
31770                // - set next charge date 
31771                $nextChargeDate = $liteNxtChargeDate = $this->User->getNextChargeDate();
31772                $saveUserArr['next_charge_date'] = $nextChargeDate;
31773            }
31774
31775            // update the user information
31776            $this->User->validate = array();
31777            if (!$read = $this->User->read(array_keys($saveUserArr), $userId)) {
31778                $this->log(__METHOD__ . ' User id does not exist. ' . json_encode($userData) . ' -- ' . json_encode($createOrderResult), $logFileName);
31779                $dataSource->rollback();
31780                return $result;
31781            }
31782
31783            $this->User->set($saveUserArr);
31784            if (!$this->User->save()) {
31785                $this->log(__METHOD__ . ' Failed update user data. ' . json_encode($saveUserArr) . ' -- ' . json_encode($createOrderResult), $logFileName);
31786                $dataSource->rollback();
31787                return $result;
31788            }
31789
31790            // get reserve payment receivable
31791            $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userId);
31792
31793            // get live lesson payment receivable
31794            $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('appreciation_data.payment_element_type'));
31795
31796            // get live lesson payment receivable
31797            $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.live'));
31798
31799            $membershipStatusIndex = UserTable::getStudentMembershipStatus($userId);
31800
31801            $discountOption = isset($data['discountOption']) ? $data['discountOption'] : [];
31802            // create discount term if user change plan to premium with annual discount option
31803            if ($discountOption) {
31804                // set data for user discount option term
31805                $udotData = [
31806                    'userId' => $userId,
31807                    'discountOptionId' => $discountOption['discount_option_id'],
31808                    'discountOptionPriceId' => $discountOption['discount_option_price_id'],
31809                    'contractStart' => date('Y-m-d 00:00:00'),
31810                    'logFileName' => $logFileName,
31811                    'paymentId' => $paymentId,
31812                    'discountAmount' => $discountOption['amount'],
31813                    'doshEvent' => $discountOption['dosh_event'],
31814                    'currencyCode' => $currencyCode,
31815                    'doshStatus' => $discountOption['dosh_status'],
31816                    'formType' => $formType
31817                ];
31818
31819                // create user discount option term
31820                if (!$this->UserDiscountOptionsTerm->createTerm($udotData)) {
31821                    $this->log(__METHOD__ . ' Failed to create user discount option term. ' . json_encode($udotData) . ' -- ' . json_encode($createOrderResult), $logFileName);
31822                    $dataSource->rollback();
31823                    return $result;
31824                }
31825
31826                $adoLogParams = [
31827                    'user_id' => $userId,
31828                    'platform' => $platform,
31829                    'status' => 1, // subscribe
31830                    'controller_name' => $this->request->params['controller'],
31831                    'action_name' => $this->request->params['action'],
31832                    'user_type' => 0, // normal user
31833                    'option_before' => '',
31834                    'option_after' => 1,
31835                    'option_before_name' => '',
31836                    'option_after_name' => 'Annual Discount Option',
31837                    'option_type' => 3, // annual discount option
31838                    'payment_plan_id' => $paymentPlanId
31839                ];
31840
31841                if (!$this->UserOptionChangeLog->saveOptionChangeLog($adoLogParams)) {
31842                    $this->log(__METHOD__ . ' Failed to update option change. ' . json_encode($adoLogParams), $logFileName);
31843                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update option change. ', $adoLogParams);
31844                    $dataSource->rollback();
31845                    return $result;
31846                }
31847            }
31848
31849            // receivable
31850            if ($receivablePayment) {
31851            
31852                $paymentData = array(
31853                    'user_id' => $userId,
31854                    'amount' => $receivablePayment,
31855                    'status' => 1,
31856                    'type_id' => 1,
31857                    'reference_id' => $userId,
31858                    'card_company' => $cardCompany,
31859                    'param1' => json_encode($data),
31860                    'form_type' => Configure::read('payment_credit_receivable'),
31861                    'ordd' => $paymentHash,
31862                    'currency_code' => $currencyCode,
31863                    'transaction_code' => $paymentHash,
31864                    'price_id' => $priceId,
31865                    'payment_id' => $paymentPlanId,
31866                    'payment_type' => $paymentType,
31867                    'discounted_amount' => 0
31868                );
31869
31870                // create new payment
31871                $this->Payment->clear();
31872                $this->Payment->create();
31873                $this->Payment->set($paymentData);
31874                $this->Payment->validate = array();
31875
31876                if (!$this->Payment->save()) {
31877                    $this->log(__METHOD__ . ' Failed to save payment data for receivable.' . json_encode($paymentData), $logFileName);
31878                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data for receivable.', $paymentData);
31879                    $dataSource->rollback();
31880                    return $result;
31881                }
31882
31883                    //update/add user`s settlement amount
31884                $this->User->updateUserPayments($paymentData);
31885                // set payment_id
31886                $paymentIdn = $this->Payment->id;
31887                
31888                // set payment receivable statuses to 2 - received
31889                $this->PaymentReceivable->updateReceivableReservationPayment(
31890                    $userId,
31891                    array(
31892                        'status' => 2,
31893                        'payment_id' => $paymentIdn,
31894                        'payment_collection_date' => date("Y-m-d H:i:s"),
31895                        'card_company' => $cardCompany,
31896                        'payment_plan_id' => $paymentPlanId,
31897                        'membership_type_index' => $membershipStatusIndex
31898                    ),
31899                    array(
31900                        'PaymentReceivable.user_id' => $userId,
31901                        'PaymentReceivable.status' => 0,
31902                        'PaymentReceivable.payment_element_type' => 1,
31903                        'PaymentReceivable.created <=' => date("Y-m-d H:i:s")
31904                    )
31905                );
31906            }
31907
31908            if ($appreciationReceivable) {
31909                // set variables
31910                $paymentData = array(
31911                    'user_id' => $userId,
31912                    'amount' => $appreciationReceivable,
31913                    'status' => 1,
31914                    'type_id' => 1,
31915                    'reference_id' => $userId,
31916                    'card_company' => $cardCompany,
31917                    'param1' => json_encode($data),
31918                    'form_type' => Configure::read('appreciation_data.payment_form_type'),
31919                    'ordd' => $paymentHash,
31920                    'currency_code' => $currencyCode,
31921                    'transaction_code' => $paymentHash,
31922                    'price_id' => $priceId,
31923                    'payment_id' => $paymentPlanId,
31924                    'payment_type' => $paymentType,
31925                    'discounted_amount' => 0
31926                );
31927
31928                // create new payment
31929                $this->Payment->clear();
31930                $this->Payment->create();
31931                $this->Payment->set($paymentData);
31932                $this->Payment->validate = array();
31933
31934                    if (!$this->Payment->save()) {
31935                    $this->log(__METHOD__ . ' Failed to save appreciation receivable payment data for receivable.' . json_encode($paymentData), $logFileName);
31936                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data for receivable.', $paymentData);
31937                    $dataSource->rollback();
31938                    return $result;
31939                }
31940                //update/add user`s settlement amount
31941                $this->User->updateUserPayments($paymentData);
31942                // set payment_id
31943                $paymentIdn = $this->Payment->id;
31944
31945                $this->PaymentReceivable->updateReceivableReservationPayment(
31946                    $userId,
31947                    array(
31948                        'status' => 2,
31949                        'payment_id' => $paymentIdn,
31950                        'payment_collection_date' => date("Y-m-d H:i:s"),
31951                        'card_company' => $cardCompany,
31952                        'payment_plan_id' => $paymentPlanId,
31953                        'membership_type_index' => $membershipStatusIndex
31954                    ),
31955                    array(
31956                        'PaymentReceivable.user_id' => $userId,
31957                        'PaymentReceivable.status' => 0,
31958                        'PaymentReceivable.payment_element_type' => Configure::read('appreciation_data.payment_element_type'),
31959                        'PaymentReceivable.created <=' => date("Y-m-d H:i:s")
31960                    )
31961                );
31962            }
31963
31964            if ($liveLessonReceivable) {
31965                $paymentData = array(
31966                    'user_id' => $userId,
31967                    'amount' => $liveLessonReceivable,
31968                    'status' => 1,
31969                    'type_id' => 1,
31970                    'reference_id' => $userId,
31971                    'card_company' => $cardCompany,
31972                    'param1' => json_encode($data),
31973                    'form_type' => Configure::read('payment_live_lesson_receivable'),
31974                    'ordd' => $paymentHash,
31975                    'currency_code' => $currencyCode,
31976                    'transaction_code' => $paymentHash,
31977                    'price_id' => $priceId,
31978                    'payment_id' => $paymentPlanId,
31979                    'payment_type' => $paymentType,
31980                    'discounted_amount' => $discountedAmount
31981                );
31982
31983                // create new payment
31984                $this->Payment->clear();
31985                $this->Payment->create();
31986                $this->Payment->set($paymentData);
31987                $this->Payment->validate = array();
31988
31989                if (!$this->Payment->save()) {
31990                    $this->log(__METHOD__ . ' Failed to save payment data for receivable.' . json_encode($paymentData), $logFileName);
31991                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data for receivable.', $paymentData);
31992                    $dataSource->rollback();
31993                    return $result;
31994                }
31995
31996                //update/add user`s settlement amount
31997                $this->User->updateUserPayments($paymentData);
31998                // set payment_id
31999                $paymentIdn = $this->Payment->id;
32000
32001                // set live lesson payment receivable statuses to 2 - received
32002                $this->PaymentReceivable->updateReceivableReservationPayment(
32003                    $userId,
32004                    array(
32005                        'status' => 2,
32006                        'payment_id' => $paymentIdn,
32007                        'payment_collection_date' => date("Y-m-d H:i:s"),
32008                        'card_company' => $cardCompany,
32009                        'payment_plan_id' => $paymentPlanId,
32010                        'membership_type_index' => $membershipStatusIndex
32011                    ),
32012                    array(
32013                        'PaymentReceivable.user_id' => $userId,
32014                        'PaymentReceivable.status' => 0,
32015                        'PaymentReceivable.payment_element_type' => Configure::read('payment_element_type.live'),
32016                        'PaymentReceivable.created <=' => date("Y-m-d H:i:s")
32017                    )
32018                );
32019            }
32020
32021
32022            $ptPaymentParams = json_decode($pt['payment_params'], true);
32023            $currency_before = $user['currency_code'];
32024            $plan_before = $user['payment_plan_id'];
32025
32026            $this->User->openDBReplica();
32027            $currentUser = $this->User->find('first', array(
32028                'fields' => array('User.parent_id', 'User.currency_code', 'User.payment_plan_id','User.memo','User.native_option','User.callan_option'),
32029                'conditions' => array('User.id' => $userId),
32030                'recursive' => -1
32031            ));
32032            $this->User->closeDBReplica();
32033
32034            $parentId = $currentUser['User']['parent_id'];
32035            
32036             
32037            $currency_after = $currentUser['User']['currency_code'];
32038            $plan_after = $currentUser['User']['payment_plan_id'];
32039            $nativeOptionBefore = $nativeOptionAfter = $currentUser['User']['native_option'];
32040            $callanOptionBefore = $callanOptionAfter = $currentUser['User']['callan_option'];
32041
32042
32043            // check if membership status was change
32044            if (isset($ptPaymentParams['statusBefore']) && isset($ptPaymentParams['statusAfter']) && isset($ptPaymentParams['platform'])) {
32045
32046                $usclData = array(
32047                    'user_id' => $userId,
32048                    'platform' => $platform ?? '',
32049                    'card_company_before' => $user['card_company'],
32050                    'status_before' => $ptPaymentParams['statusBefore'],
32051                    'status_after' => $ptPaymentParams['statusAfter'],
32052                    'controller_name' => $this->request->params['controller'],
32053                    'action_name' => $this->request->params['action'],
32054                    'is_cron' => $is_cron,
32055                    'currency_before' => $currency_before,
32056                    'currency_after' => $currency_after,
32057                    'payment_plan_id_before' => $plan_before,
32058                    'payment_plan_id_after' => $plan_after,
32059                );
32060                // save user change membership status
32061                if (!$this->UserStatusChangeLog->saveLog($usclData)) {
32062                    $dataSource->rollback();
32063                    return $result;
32064                }
32065            }
32066
32067            $isLitePlanUser = in_array($plan_after,Configure::read('lite_payment_plans')) ? true : false;
32068            $offUnlimitedOptionNativeFlg = (isset($data['offUnlimitedOptionNative']) && $data['offUnlimitedOptionNative']) ? true : false;
32069            $offUnlimitedOptionCallanFlg = (isset($data['offUnlimitedOptionCallan']) && $data['offUnlimitedOptionCallan']) ? true : false;
32070            $giveLiteMonthlyCoinFlg = (isset($data['giveLiteMonthlyCoin']) && $data['giveLiteMonthlyCoin']) ? true : false;
32071            $removeAllHeldCoinsFlg = (isset($data['removeAllHeldCoins']) && $data['removeAllHeldCoins']) ? true : false;
32072
32073            $currentMemo = $currentUser['User']['memo'];
32074            $updateMemo = '';
32075            $memoCoins = 'MC';
32076            $userUpdateArr = array();
32077            $isNativeOptionChange = $isCallanOptionChange = false;
32078            $today = date('Y-m-d');
32079
32080            // - turn off native option if it is on
32081            if ($offUnlimitedOptionNativeFlg && (int) $nativeOptionBefore == 1) {
32082                    $userUpdateArr['native_option'] = 0; // turn off
32083                    $userUpdateArr['native_option_cancellation_time'] = $dateNow;
32084                    $nativeOptionAfter = 0;
32085                    $isNativeOptionChange = true;
32086
32087                    // set memo
32088                    $updateMemo = $updateMemo. "\n{$today} \nChanged by due Selected Light Plan / Native Unlimited option OFF";
32089            }
32090
32091            // - turn off callan option if it is on
32092            if ($offUnlimitedOptionCallanFlg && (int) $callanOptionBefore == 1) {
32093                $userUpdateArr['callan_option'] = 0; // turn off
32094                $userUpdateArr['callan_option_cancellation_time'] = $dateNow;
32095                $callanOptionAfter = 0;
32096                $isCallanOptionChange = true;
32097
32098                $updateMemo = $updateMemo. "\n{$today} \nChanged by due Selected Light Plan / Callan Unlimited option OFF";
32099            }
32100
32101    
32102            // - confiscate lite plan bonus coin 
32103            if ($removeAllHeldCoinsFlg || $formType == Configure::read('payment_lite_plan_downgrade')) {
32104                    // - fetch users mc coins
32105                    $_monthlyPoints = $this->UsersPoint->getCurrentUserMCPoint($userId); //  mc coins
32106
32107                    if ((int) $_monthlyPoints > 0) {
32108                    
32109                        $confiscateParams = array(
32110                            'userId' => $userId,
32111                            'point' => $_monthlyPoints,
32112                            'kbn' => 18, 
32113                            'coinType' => 3
32114                        );
32115
32116                        // rollback if confiscating points failed
32117                        if (!$confiscateCoinFlg = $this->UsersPoint->confiscateUserLitePoints($confiscateParams)) {
32118                            $this->log(__METHOD__ . ' Failed to confiscate points. --> ' . json_encode($confiscateParams) . ' -- ' . json_encode($data), $logFileName);
32119                                    
32120                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to confiscate points.', $data);
32121                            $dataSource->rollback();
32122                            
32123                            return $result;
32124                        }
32125
32126                        $updateMemo = $updateMemo . "\n {$dateNow} (Previous Coins ({$memoCoins})【Confiscated】 : {$_monthlyPoints}. )";
32127                    }
32128
32129                    $_doneConfiscatePoints = ClassRegistry::init('UsersPointHistory')->confiscateUserLitePointsCoinBox($userId);
32130            }
32131
32132            // - NJ-18780 : add monthly coin for lite plan user 
32133            if ($formType == Configure::read('payment_lite_plan_downgrade')) {
32134                        
32135                    // - set to add monthly coin
32136                    $_pointParams = array(
32137                        'userId' => $userId,
32138                        'point' => Configure::read('lite_plan_monthly_coin'),
32139                        'kbn' => Configure::read('lite_plan_bonus_kbn'), // 
32140                        'kbnType' => 1, // add coin
32141                        'coinType' => 3, // mc coin
32142                        'dateExpiration' => $liteNxtChargeDate,
32143                        'coinFailMessage' => Configure::read('coin.failed.membership')
32144                    );
32145
32146
32147                    // rollback if adding  points failed
32148                    if (!$addCoinsFlg = $this->UsersPoint->performPointTransaction($_pointParams)) {
32149                        $this->log(__METHOD__ . ' Failed to give points. --> ' . json_encode($confiscateParams) . ' -- ' . json_encode($data), $logFileName);
32150                                    
32151                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to give points.', $data);
32152                        $dataSource->rollback();
32153                            
32154                        return $result;
32155                    }
32156
32157                    $_coins = Configure::read('lite_plan_monthly_coin');
32158                    $updateMemo = $updateMemo . "\n {$dateNow} | Light Plan Bonus Coins (MC): {$_coins}";
32159            }
32160
32161    
32162            // - update user memo
32163            if (!empty($updateMemo)) {
32164                $updateMemo = $updateMemo . "\n" . $currentMemo;
32165                $this->User->read(array('memo'), $userId);
32166                $this->User->set(array('memo' => $updateMemo));
32167                $this->User->validate = array();
32168
32169                // rollback if updating memo failed
32170                if (!$this->User->save()) {
32171                    $this->log(__METHOD__ . ' Failed update user memo. ' . json_encode($updateMemo) . ' -- ' . json_encode($data), $logFileName);
32172                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed update user memo.', $data);
32173                    $dataSource->rollback();
32174                    return $result;
32175                }
32176            }
32177
32178            // - update user information
32179            if ($userUpdateArr) {
32180                $userUpdateArr['id'] = $userId;
32181
32182                $this->User->clear();
32183                $this->User->set($userUpdateArr);
32184                $this->User->validate = array();
32185
32186                // rollback if updating memo failed
32187                if (!$this->User->save()) {
32188                    $this->log(__METHOD__ . ' Failed update user info. ' . json_encode($userUpdateArr) . ' -- ' . json_encode($data), $logFileName);
32189                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed update user memo.', $data);
32190                    $dataSource->rollback();
32191                    return $result;
32192                }
32193            }
32194
32195            // - add native option change log
32196            if ($isNativeOptionChange) {
32197                // add native option change logs
32198                if ($nativeOptionAfter) {
32199                    $nativeStatus = 1; // subscribed
32200                    $statusBefore = $option_before_name = '';
32201                    $option_after_name = 'Native Unlimited Option';
32202                    $statusAfter = 1; //
32203                } else {
32204                    $nativeStatus = 3; // unsubscribed
32205                    $statusBefore = 1;
32206                    $option_before_name = 'Native Unlimited Option';
32207                    $option_after_name = $statusAfter = '';
32208                }
32209
32210
32211                $optionLogParams = array(
32212                    'user_id' => $userId,
32213                    'platform' => Configure::read('platform.pclp'),
32214                    'status' => $nativeStatus,
32215                    'controller_name' => $this->request->params['controller'],
32216                    'action_name' => $this->request->params['action'],
32217                    'user_type' => 0, // user
32218                    'option_before' => $statusBefore,
32219                    'option_after' => $statusAfter,
32220                    'option_before_name' => $option_before_name,
32221                    'option_after_name' => $option_after_name,
32222                    'option_type' => 1,
32223                    'payment_plan_id' => $plan_after
32224                );
32225
32226                $aveLog = ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
32227
32228                // rollback if confiscating points failed
32229                if (!$aveLog) {
32230                    $this->log(__METHOD__ . ' Failed to save user option change log. --> ' . json_encode($optionLogParams) . ' -- ' . json_encode($data), $logFileName);
32231                                
32232                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save option log.', $optionLogParams);
32233                    $dataSource->rollback();
32234                        
32235                    return $result;
32236                }
32237            }
32238
32239
32240            // - add callan option change log
32241            if ($isCallanOptionChange) {
32242                // add callan option change logs
32243                if ($callanOptionAfter) {
32244                    $callanStatus = 1; // subscribed
32245                    $statusBefore = $option_before_name = '';
32246                    $option_after_name = 'Callan Unlimited Option';
32247                    $statusAfter = 1; //
32248                } else {
32249                    $callanStatus = 3; // unsubscribed
32250                    $statusBefore = 1;
32251                    $option_before_name = 'Callan Unlimited Option';
32252                    $option_after_name = $statusAfter = '';
32253                }
32254
32255                $optionLogParams = array(
32256                    'user_id' => $userId,
32257                    'platform' => Configure::read('platform.pclp'),
32258                    'status' => $callanStatus,
32259                    'controller_name' => $this->request->params['controller'],
32260                    'action_name' => $this->request->params['action'],
32261                    'user_type' => 0, // user
32262                    'option_before' => $statusBefore,
32263                    'option_after' => $statusAfter,
32264                    'option_before_name' => $option_before_name,
32265                    'option_after_name' => $option_after_name,
32266                    'option_type' => 2,
32267                    'payment_plan_id' => $plan_after
32268                );
32269
32270                $aveLog = ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
32271
32272                // rollback if confiscating points failed
32273                if (!$aveLog) {
32274                    $this->log(__METHOD__ . ' Failed to save user option change log. --> ' . json_encode($optionLogParams) . ' -- ' . json_encode($data), $logFileName);
32275                                
32276                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save option log.', $optionLogParams);
32277                    $dataSource->rollback();
32278                        
32279                    return $result;
32280                }
32281            }
32282
32283            $ptUpdateParams = array(
32284                'id' => $mpptId,
32285                'fields' => array(
32286                    'status' => 1,
32287                    'response_text' => $createOrderResult
32288                ),
32289                'logFileName' => $logFileName
32290            );
32291
32292            // update monthly payment payment transaction
32293            if (!$this->PaymentTransaction->updateWPPaymentTransaction($ptUpdateParams)) {
32294                $this->log(__METHOD__ . ' Failed to update payment transaction. --> ' . json_encode($ptUpdateParams), $logFileName);
32295                $dataSource->rollback();
32296                return $result;
32297            }
32298
32299            //- change to chocotto camp plan
32300            if (in_array(
32301                    $formType,
32302                    [
32303                        Configure::read('payment_credit_chocotto_monthly_payment'),
32304                        Configure::read('payment_credit_chocotto_retry'),
32305                    ]
32306            )) {
32307                //- confiscate lite points
32308                UserTable::changePlanProcess(['user_id' => $userId]);
32309            }
32310
32311            try {
32312                $dataSource->commit();
32313            } catch (\Throwable $th) {
32314                $this->log(__METHOD__ . ' Catch transaction error. --> ' . json_encode($th->getMessage()), $logFileName);
32315            }
32316
32317            $result['success'] = true;
32318        } else {
32319            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Paypal change plan process - failed to create order', $paypalData, $createOrderParams);
32320        }
32321
32322        // delete memcache
32323        if ($this->memcache->get('process_change_plan_'.$userId)) {
32324            $this->memcache->delete('process_change_plan_'.$userId);
32325        }
32326
32327        return $result;
32328    }
32329
32330    private function zeus_payment_change_plan($data = array(),$user=array()){
32331
32332        $logFileName = 'monthly_payment';
32333
32334        if (!$user || !$data) {
32335            $this->log(__METHOD__ . ' Missing billing agreement param(s). --> ' . json_encode($user), $logFileName);
32336            return false;
32337        }
32338
32339        $formType = $data['formType'] ?? null;
32340
32341        if (!$formType) {
32342            $this->log(__METHOD__ . ' Missing form type param(s). --> ' . json_encode($data), $logFileName);
32343            return false;
32344        }
32345
32346        if (!$data['statusAfter']) {
32347            $this->log(__METHOD__ . ' Missing statusAfter param(s). --> ' . json_encode($data), $logFileName);
32348            return false;
32349        }
32350
32351        if (!$data['paymentPlanData']) {
32352            $this->log(__METHOD__ . ' Missing paymentPlanData param(s). --> ' . json_encode($data), $logFileName);
32353            return false;
32354        }
32355
32356        if (!isset($data['totalPayment'])) {
32357            $this->log(__METHOD__ . ' Missing totalPayment param(s). --> ' . json_encode($data), $logFileName);
32358            return false;
32359        }
32360
32361        if (!isset($data['charge_payment_flg'])) {
32362            $this->log(__METHOD__ . ' Missing charge_payment_flg param(s). --> ' . json_encode($data), $logFileName);
32363            return false;
32364        }
32365
32366        $result = false;
32367
32368        // - init var 
32369        $currencyCode = $user['currency_code'];
32370         $priceId = $data['paymentPlanData']['priceId'];
32371         $paymentPlanId = $data['paymentPlanData']['paymentPlanId'];
32372        $currency_before = $user['currency_code'];
32373        $plan_before = $payingUser['User']['payment_plan_id'];
32374        $discountAmount = $monthlyPayment = $totalPayment = 0;
32375        $sendId = $user['id'];
32376
32377        // - update user for creating payment transaction
32378        $user['payment_plan_id'] = $data['paymentPlanData']['paymentPlanId'];
32379        $user['price_id'] = $data['paymentPlanData']['priceId'];
32380
32381        $monthlyPayment = $totalPayment = $data['totalPayment'];
32382        $email = $user['email'];
32383        $clientIp = PaymentTable::getClientIpByCompanyId($user["card_company"]);
32384        $familyId = null;
32385
32386        $nativeOptionPayment = $callanOptionPayment = 0;
32387        $chargePaymentFlg = (isset($data['charge_payment_flg']) && $data['charge_payment_flg']) ? 1 : 0;
32388
32389
32390          $paymentParams = array(
32391            'currencyCode' => $currencyCode,
32392            'formType' => $formType,
32393            'paymentType' => Configure::read('payment_types.payment_plan'),
32394            'logFileName' => $logFileName,
32395            'paymentAmount' => $totalPayment,
32396            'familyId' => $familyId,
32397            'priceId' => $priceId,
32398            'paymentPlanId' => $paymentPlanId,
32399            'nativeOptionPayment' => $nativeOptionPayment,
32400            'callanOptionPayment' => $callanOptionPayment,
32401            'platform' => $user['platform'],
32402            'statusBefore' => $data['statusBefore'],
32403            'statusAfter' => $data['statusAfter'],
32404            'changePlanChargeFlg' => $chargePaymentFlg 
32405          );
32406
32407        if (isset($data['discountOption'])) {
32408            $paymentParams['discountOption'] = $data['discountOption'];
32409            $paymentParams['discountOption'] += [
32410                'dosh_type' => Configure::read('discount_option.dosh_type.plan_change'),
32411                'dosh_status' => Configure::read('discount_option.dosh_status.subscription'),
32412                'option_after_name' => 'Annual Discount Option',
32413                'option_type' => 3
32414            ];
32415        }
32416
32417          $userId =  $sendId;
32418
32419          $paymentHash = myTools::generateOrderCode($userId);
32420
32421        $ptParams = array(
32422            'user_id' => $userId,
32423            'payment_hash' => $paymentHash,
32424            'payment_params' => json_encode($paymentParams),
32425            'course_id' => Configure::read("credit.course_id")
32426        );
32427
32428
32429        // create payment transaction
32430        if (!$pt = $this->PaymentTransaction->setWPPaymentTransaction($ptParams)) {
32431              $this->log(__METHOD__ . ' Failed to create payment transaction . --> ' . json_encode($ptParams), $logFileName);
32432            return false;
32433        }
32434
32435        $this->log(__METHOD__ . '  payment transaction. --> ' . json_encode($pt), $logFileName);
32436
32437        $result = false;
32438
32439        $params = array(
32440            'clientIp' => $clientIp,
32441            'email' => $email,
32442            'sendId' => $sendId,
32443            'money' => $totalPayment,
32444            'paymentHash' => $paymentHash
32445        );
32446
32447         // perform curl request
32448          $curlPayment = ZChargeComponent::charge_with_regsterd_card(json_encode($params));
32449
32450          if ($curlPayment === "Success_order") {
32451              $result = true;
32452          }
32453
32454         // delete memcache
32455        if ($this->memcache->get('process_change_plan_'.$userId)) {
32456            $this->memcache->delete('process_change_plan_'.$userId);
32457        }
32458
32459
32460        return [
32461            'success' => $result,
32462            'paymentHash' => $paymentHash
32463        ];
32464    }
32465    /**
32466     * @api {get} /payment/payment_credit_register_receivable payment_credit_register_receivable()
32467     * @apiName payment_credit_register_receivable
32468     * @apiGroup Payment
32469     * @apiDescription This endpoint is used to redirect to zeus_credit_change or wp_credit_change based on user currency.
32470     * 
32471     * @apiParam {String} [disabled] If set, the page will be disabled.
32472     * 
32473     * @apiSuccess {View} Redirect Redirects to zeus_credit_change for jpy currency
32474     * @apiSuccess {View} Redirect Redirects to wp_credit_change for all other currencies
32475     * 
32476     * @apiError {View} Redirect Redirects to {{ENV}}/ if user membership type is not in payment_receivable
32477     * 
32478     * @apiSuccessExample Success Response JPY currency:
32479     * Redirects to zeus_credit_change
32480     * 
32481     * @apiSuccessExample Success Response All other currencies:
32482     * Redirects to wp_credit_change
32483     * 
32484     * @apiErrorExample Error Response:
32485     * Redirects to {{ENV}}/
32486     * 
32487     * @apiSampleRequest off
32488     */
32489    public function payment_credit_register_receivable() {
32490        $this->blockWithdrawnSapuriToS();
32491        $this->disablePageForSapuri();
32492        $user = $this->sharedUserData['User'];
32493        $userObj = new UserTable($user);
32494        if(!empty($user['corporate_id']) && in_array($userObj->getMembershipTypeIndex(), Configure::read('common_corporate_payment_memberships'))) {
32495            return $this->redirect(myTools::getUrl() . '/common_corporate_payment?type=' . Configure::read('payment_url_type.corporate_type.corporate_change_payment_credit'));
32496        }
32497        
32498        if (!$memcache_receivable_data = $this->memcache->get('memcache_receivable_data' . $user['id'])) {
32499            throw new NotFoundException();
32500        }
32501
32502        $zeusMaintenance = false;
32503        if (myTools::zeusMaintenancePeriod()){
32504            $zeusMaintenance = true;
32505        }
32506        $isCardRegistered = false;
32507        if ((!empty($user['card_brand']) && !empty($user['card_number']))) {
32508            $isCardRegistered = true;
32509        }
32510
32511        $telecomDisabled = false;
32512        $formType = Configure::read('payment_credit_change');
32513        $requestData = $this->request->query;
32514        if (!isset($requestData["disabled"])) {
32515            $this->checkUser($formType);
32516        } else {
32517            $telecomDisabled = true;
32518        }
32519
32520        $userObj = new UserTable($user);
32521        $membershipType = $userObj->getMembershipTypeIndex();
32522        if (!in_array($membershipType, Configure::read('membership_type.payment_receivable'))) {
32523            return $this->redirect('/');
32524        }
32525
32526        $users_detail = $userObj->individualCardFailFlg();
32527        $this->set('individual_card_fail_flg', $users_detail['individual_card_fail_flg'] ?? 0);
32528
32529        $this->getAndSetCardInfo($user);
32530
32531        $this->set('zeus_maintenance', $zeusMaintenance);
32532        $this->set('corporateFlg', myTools::getCoporateTypeUsingPaymentPlanId($user['payment_plan_id']));
32533        $this->set('isCardRegistered', $isCardRegistered);
32534        $this->set("telecomDisabled", $telecomDisabled);
32535        $this->set("membershipType", $membershipType);
32536        $this->set('zeusTransactionFlag', true);
32537        $this->setSupportPayPal($userData);
32538
32539        $zeroStudentDiscountOptionUser = false;
32540
32541        // if light plan user
32542        if (in_array($membershipType, Configure::read('membership_type_lightplan'))) {
32543            // get user active zero student discount option data
32544            $zeroStudentDiscountOptionTermData = $this->UserDiscountOptionsTerm->getTerm([
32545                'user_id' => $userObj->id,
32546                'discount_option_id' => Configure::read('discount_option.zero_student.plan_id'),
32547                'status' => 1
32548            ]);
32549
32550            // set to true if zero student discount option user
32551            if ($zeroStudentDiscountOptionTermData) {
32552                $zeroStudentDiscountOptionUser = true;
32553            }
32554        }
32555
32556        $this->set('zeroStudentDiscountOptionUser', $zeroStudentDiscountOptionUser);
32557
32558        // redirect to zeus if currency is equals to jpy
32559        if ($this->sharedUserData['User']['currency_code'] == Configure::read('default.user_currency')) {
32560            $this->zeus_credit_change();
32561        // redirect to wp
32562        } else {
32563            $this->wp_credit_change();
32564        }
32565    }
32566    /**
32567     * @api {post} /payment/createCorporateIndividualPayment/:corporatePlan createCorporateIndividualPayment()
32568     * @apiName createCorporateIndividualPayment
32569     * @apiGroup Payment
32570     * @apiDescription This endpoint is used to create corporate individual payment.
32571     * 
32572     * @apiParam {String} [corpMobApp] If set, the payment is for mobile app.
32573     * @apiParam {String} [userApiToken] User API token.
32574     * @apiParam {String} corporatePlan Corporate plan type (light, premium, standard).
32575     * 
32576     * @apiSuccess {String} paymentHash The payment hash.
32577     * @apiSuccess {Number} paymentAmount The payment amount.
32578     * 
32579     * @apiError {String} paymentHash The payment hash. Empty if payment is not created.
32580     * @apiError {Number} paymentAmount The payment amount. 0 if payment is not created.
32581     * 
32582     * @apiSuccessExample Success Response:
32583     * {
32584     *   "paymentHash": "some_payment_hash",
32585     *   "paymentAmount": 1000
32586     * }
32587     * 
32588     * @apiErrorExample Success Response:
32589     * {
32590     *   "paymentHash": "",
32591     *   "paymentAmount": 0
32592     * }
32593     */
32594    public function createCorporateIndividualPayment($data) {
32595        $this->autoLayout = false;
32596        $this->autoRender = false;
32597
32598        $corporateTaxRate = Configure::read('tax.increase');
32599
32600        if( isset($data['corpMobApp']) ) {
32601            if( isset($data['userData']) ) {
32602                $user = $data['userData'];
32603            } else {
32604                $mobAppUserData = $this->User->findByApiToken($data['userApiToken']);
32605                $user = $mobAppUserData['User'];
32606            }
32607            $corpSessionKeyMobApp = 'mobappUserCreditChargeInfo_'.$data['userApiToken'];
32608        } else {
32609            $user = $this->sharedUserData['User'];
32610            $corpSessionKey = 'PaymentCreditChargeCorporateData';
32611        }
32612
32613        if( isset($data['ZPaymentFullLogs']['corporatePlan']) ) {
32614
32615            if($data['ZPaymentFullLogs']['corporatePlan'] == 'light') {
32616                $getPaymentPlanId = $this->getCorporatePaymentPlan($user,array('corporate_type' => 4));
32617                $getLightCorporateData = $this->Corporate->getCorporateLightUserMonthly(array(
32618                    'user_id' => $user['id'],
32619                    'remove_heavy_flg' => true
32620                ));
32621                $paymentLightAmount = isset($getLightCorporateData['total']) ? $getLightCorporateData['total'] : 0;
32622                $basicLightFee = isset($getLightCorporateData['basic_fee']) ? $getLightCorporateData['basic_fee'] : 0;
32623                $lessonLightFee = isset($getLightCorporateData['lesson_fee']) ? $getLightCorporateData['lesson_fee'] : 0;
32624                $basicLightFeeWoTax = isset($getLightCorporateData['basic_fee_discounted']) ? $getLightCorporateData['basic_fee_discounted'] : 0;
32625                $freeLightNumber = isset($getLightCorporateData['fee_charge_count']) ? $getLightCorporateData['fee_charge_count'] : 0;
32626                $isLightFreeFlg = isset($getLightCorporateData['free_charge_flg']) ? $getLightCorporateData['free_charge_flg'] : false;
32627                $monthlyLightFee = isset($getLightCorporateData['monthly_fee_wo_tax']) ? $getLightCorporateData['monthly_fee_wo_tax'] : 0;
32628                $cfLightAmount = myTools::formatAmount($basicLightFeeWoTax);
32629                $cLightRawAmount = $basicLightFeeWoTax;
32630                $lessonLightLimit = $this->Corporate->getLessonLimit($user['corporate_id']);
32631                $cpData = array(
32632                    'basicFee' => $basicLightFee,
32633                    'lessonFee' => $lessonLightFee,
32634                    'freeFlg' => $isLightFreeFlg,
32635                    'freeNumber' => $freeLightNumber,
32636                    'monthlyFee' => $monthlyLightFee,
32637                    'fAmount' => $cfLightAmount,
32638                    'paymentAmount' => $paymentLightAmount,
32639                    'lessonLimit' => $lessonLightLimit,
32640                    'paymentPlanId' => $getPaymentPlanId['paymentPlanId'],
32641                    'cRawAmount'    => $cLightRawAmount,
32642                    'basicFeeWoTax' => $basicLightFeeWoTax,
32643                    'priceId'        => $getPaymentPlanId['priceId']
32644                );
32645
32646                $data['ZPaymentFullLogs']['indiCorpType'] = 4;
32647            } else if($data['ZPaymentFullLogs']['corporatePlan'] == 'premium') {
32648                $cpPremuimData = $this->getCorporatePaymentPlan($user,array('corporate_type' => 2));
32649                
32650                $cdrPremiumParam = array('corporateId' => $user['corporate_id'], 'corporateType' => 2);
32651                $discountPremium = (int)$this->CorporateDiscountRate->getDiscount($cdrPremiumParam);
32652                $cPremiumAmount = (int)$cpPremuimData['amount'] - $discountPremium;
32653                $cPremiumRawAmount = $cPremiumAmount;
32654                $cfPremiumAmount = myTools::formatAmount($cPremiumAmount);
32655                $cpData = array(
32656                    'cprAmount' => $cpPremuimData['amount'],
32657                    'cprDiscount' => $discountPremium,
32658                    'paymentAmount' => $cPremiumAmount * $corporateTaxRate,
32659                    'fAmount' => $cfPremiumAmount,
32660                    'cRawAmount' => $cPremiumRawAmount,
32661                    'ppAmount' => $cpPremuimData,
32662                    'paymentPlanId' => $cpPremuimData['paymentPlanId'],
32663                    'priceId'        => $cpPremuimData['priceId']
32664                );
32665
32666                $data['ZPaymentFullLogs']['indiCorpType'] = 2;
32667            } else {
32668                $cpStandardData = $this->getCorporatePaymentPlan($user,array('corporate_type' => 1));
32669                $cdrStandardParam = array('corporateId' => $user['corporate_id'], 'corporateType' => 1);
32670                $discountStandard = (int)$this->CorporateDiscountRate->getDiscount($cdrStandardParam);
32671                $cStandardAmount = (int)$cpStandardData['amount'] - $discountStandard;
32672                $cStandardRawAmount = $cStandardAmount;
32673                $cfStandardAmount = myTools::formatAmount($cStandardAmount);
32674                $cpData = array(
32675                    'cprAmount' => $cpStandardData['amount'],
32676                    'cprDiscount' => $discountStandard,
32677                    'paymentAmount' => $cStandardAmount * $corporateTaxRate,
32678                    'fAmount' => $cfStandardAmount,
32679                    'cRawAmount' => $cStandardRawAmount,
32680                    'ppAmount' => $cpStandardData,
32681                    'paymentPlanId' => $cpStandardData['paymentPlanId'],
32682                    'priceId'        => $cpStandardData['priceId']
32683                );
32684                $data['ZPaymentFullLogs']['indiCorpType'] = 1;
32685            }
32686
32687            $corpIndiPrices = $this->Session->read('corporateIndiPrices');
32688            $corpIndiPrices[$data['ZPaymentFullLogs']['corporatePlan']]['plan_type'] = $data['ZPaymentFullLogs']['indiCorpType'];
32689
32690            if( isset($data['corpMobApp']) ) {
32691                $this->memcache->set(array(
32692                    'key' => $corpSessionKeyMobApp,
32693                    'value' => $corpIndiPrices[$data['ZPaymentFullLogs']['corporatePlan']],
32694                    'expire' => 3600 // 1 hour
32695                ));
32696                $corporateChargeMemData = $this->memcache->get('mobappCreditChargeCorporateData_' . $user['id']);
32697            } else {
32698                $this->Session->write($corpSessionKey,$corpIndiPrices[$data['ZPaymentFullLogs']['corporatePlan']]);
32699            }
32700
32701        }
32702
32703        // change payment plan id and price id
32704        $user['price_id'] = $cpData['priceId'];
32705        $user['payment_plan_id'] = $cpData['paymentPlanId'];
32706        $user['corporate_type'] = $data['ZPaymentFullLogs']['indiCorpType'];
32707        $user['corporateSettlementType'] = Configure::read('corporate_settlement_types.force_charge_payment');
32708
32709        $formType = myTools::getCorporateCompanyCardFormType($cpData['paymentPlanId']);
32710
32711        if ( $this->Session->check($corpSessionKey) || $corporateChargeMemData ) {
32712            // get reserve payment receivable
32713            $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($user['id']);
32714            // get live lesson payment receivable
32715            $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($user['id'], false, Configure::read('appreciation_data.payment_element_type'));
32716            // get live lesson payment receivable
32717            $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($user['id'], false, Configure::read('payment_element_type.live'));
32718
32719            if( isset($data['corpMobApp']) ) {
32720                $corporateIndiPaymentData = $corporateChargeMemData;
32721            } else {
32722                $corporateIndiPaymentData = $this->Session->read($corpSessionKey);
32723            }
32724            $user['paymentAmount'] = (int)$corporateIndiPaymentData['paymentAmount'] + $receivablePayment;
32725
32726            $this->log('[LoyD] createCorporateIndividualPayment cpData --> '.json_encode($cpData));
32727
32728            // corporate light
32729            if (
32730                $corporateIndiPaymentData['plan_type'] == Configure::read('corporate_type.light') &&
32731                isset($corporateIndiPaymentData['lessonFee']) &&
32732                isset($corporateIndiPaymentData['basicFee'])
32733            ) {
32734                $user['lesson_fee'] = (int)$corporateIndiPaymentData['lessonFee'];
32735                $user['basic_fee'] = (int)$corporateIndiPaymentData['basicFee'];
32736            // standard or premium
32737            } else {
32738                if (isset($corporateIndiPaymentData['cprAmount']) && isset($corporateIndiPaymentData['cprDiscount'])) {
32739                    $user['cprAmount'] = (int)$corporateIndiPaymentData['cprAmount'];
32740                    $user['cprDiscount'] = (int)$corporateIndiPaymentData['cprDiscount'];
32741                }
32742            }
32743            $membershipTypes = UserTable::getEngMembershipTypeData();
32744            $user['statusAfter'] =  myTools::getCorporateUserMembershipStatusName($membershipTypes, $user['payment_plan_id']);
32745
32746            $userTable = new UserTable($user);
32747            // add statusBefore and statusAfter if free "Trial not yet conducted"
32748            if ($userTable->getMembershipTypeIndex() == 13) {
32749                $user['statusBefore'] = $membershipTypes[13];
32750                $user['statusAfter'] = myTools::getCorporateUserMembershipStatusName($membershipTypes, $user['payment_plan_id']);
32751            }
32752        }
32753
32754        // - NJ-23812: write session to skip and auto charge check
32755        // set transaction error to 1 if failed to create payment transaction
32756        if (!$pt = $this->createPaymentTransaction($formType, $user)) {
32757            $this->set('transactionError', 1);
32758        }
32759
32760        if( isset($data['corpMobApp']) ) {
32761            $this->memcache->set(array(
32762                'key' => 'indiCorpPaymentHash_'.$user['id'],
32763                'value' => isset($pt['payment_hash']) ? $pt['payment_hash'] : "",
32764                'expire' => 3600 // 1 hour
32765            ));
32766        } else {
32767            $this->Session->write('indiCorpPaymentHash', isset($pt['payment_hash']) ? $pt['payment_hash'] : "");
32768        }
32769
32770        $response = [
32771            'paymentHash' => isset($pt['payment_hash']) ? $pt['payment_hash'] : "",
32772            'paymentAmount'    => (int)$cpData['paymentAmount']
32773        ];
32774
32775        return $response;
32776    }
32777
32778    private function getDefaultPlanId($corporateId = null) {
32779        // default selected plans for null corporate type
32780        $defaultPlan = Configure::read('payment_plans.corporate_premium_individual_plan');
32781
32782        // get corporate admin payment method
32783        $this->Corporate->openDBReplica();
32784        $getActivePlans = $this->Corporate->find('first',
32785                [
32786                    'fields' => [
32787                        'cs_display_flg',
32788                        'cp_display_flg',
32789                        'clt_display_flg',
32790                    ],
32791                    'conditions' => [
32792                        'id' => $corporateId
32793                    ],
32794                    'recursive' => -1
32795                ]
32796            );
32797        $this->Corporate->closeDBReplica();
32798
32799        if(isset($getActivePlans['Corporate']['cs_display_flg']) && $getActivePlans['Corporate']['cs_display_flg']) {
32800            $defaultPlan = Configure::read('payment_plans.corporate_standard_individual_plan');
32801        } else if(isset($getActivePlans['Corporate']['cp_display_flg']) && $getActivePlans['Corporate']['cp_display_flg']){
32802            $defaultPlan = Configure::read('payment_plans.corporate_premium_individual_plan');
32803        } else if(isset($getActivePlans['Corporate']['clt_display_flg']) && $getActivePlans['Corporate']['clt_display_flg']){
32804            $defaultPlan = Configure::read('payment_plans.corporate_light_individual_plan');
32805        }
32806        return $defaultPlan;
32807    }
32808
32809    private function selectCorpType($planId = null) {
32810        $defaultCorpType = Configure::read('corporate_type.premium');
32811        if (in_array($planId, array(Configure::read('payment_plans.corporate_standard_individual_plan'), Configure::read('payment_plans.corporate_standard_card_plan')))) {
32812            $defaultCorpType = Configure::read('corporate_type.standard');
32813        } else if ($planId == Configure::read('payment_plans.corporate_premium_individual_plan')) {
32814            $defaultCorpType = Configure::read('corporate_type.premium');
32815        } else if (in_array($planId, array(Configure::read('payment_plans.corporate_light_individual_plan'), Configure::read('payment_plans.corporate_light_card_plan')))) {
32816            $defaultCorpType = Configure::read('corporate_type.light');
32817        }
32818        return $defaultCorpType;
32819    }
32820    /**
32821     * @api {post} /payment/createLitePlanTransaction/:userId/:formType/:isNewRegister/ createLitePlanTransaction()
32822     * @apiName createLitePlanTransaction
32823     * @apiGroup Payment
32824     * @apiDescription This endpoint is used to create lite plan transaction.
32825     * 
32826     * @apiParam {String} userId User ID.
32827     * @apiParam {String} formType Form type.
32828     * @apiParam {String} isNewRegister If set to 1, the user is a new register.
32829     * @apiParam {String} [studentDiscountOptionData] Student discount option data.
32830     * 
32831     * @apiSuccess {String} paymentHash The payment hash.
32832     * @apiSuccess {Number} paymentMonthlyAmount The payment monthly amount.
32833     * 
32834     * @apiError {String} paymentHash The payment hash. Empty if payment is not created.
32835     * @apiError {Number} paymentMonthlyAmount The payment monthly amount. 0 if payment is not created.
32836     * 
32837     * @apiSuccessExample Success Response:
32838     * {
32839     *      "paymentHash": "some_payment_hash",
32840     *         "paymentMonthlyAmount": 1000
32841     * }
32842     * 
32843     * @apiErrorExample Success Response:
32844     * {
32845     *         "paymentHash": "",
32846     *         "paymentMonthlyAmount": 0
32847     * }
32848     */
32849    public function createLitePlanTransaction($params = []){
32850        $userID = isset($params['userId']) ? $params['userId'] : null;
32851        $formType = isset($params['formType']) ? $params['formType'] : null;
32852        $isNewRegister = isset($params['isNewRegister']) ? $params['isNewRegister'] : false;
32853        $studentDiscountOptionData = isset($params['studentDiscountOptionData']) ? $params['studentDiscountOptionData'] : [];
32854
32855        $result = array();
32856
32857        $logs = array(
32858            'userID' => $userID,
32859            'formType' => $formType,
32860            'isNewRegister' => $isNewRegister
32861        );
32862
32863        if ($userID) {
32864            
32865            #default plan id 
32866            $plan_id = null;
32867            $statusAfter = null;
32868            $membershipTypes = UserTable::getEngMembershipTypeData();
32869
32870            # Step 0 : set the correct form type
32871            if ($isNewRegister) {
32872                if ($studentDiscountOptionData) {
32873                    $formType = Configure::read('payment_lite_credit_monthly_payment');
32874                    $plan_id = Configure::read('payment_plans.light_plan');
32875                    $statusAfter = $membershipTypes[37]; // light plan paid
32876                } else {
32877                    # set the correct form type for newly register
32878                    $formType = Configure::read('payment_lite_credit_free');
32879                    $plan_id = Configure::read('payment_plans.light_plan_free');
32880                    $statusAfter = $membershipTypes[36];
32881                }
32882            }else{
32883
32884                $plan_id = Configure::read('payment_plans.light_plan');
32885                $statusAfter = $membershipTypes[37];
32886
32887                # set the correct form type for charge 
32888                if ($formType == Configure::read('payment_credit_force_charge')) {
32889                    $formType = Configure::read('payment_lite_credit_paid');
32890                }
32891            }
32892
32893            # Step 1 fetch user data 
32894            $userData = $this->User->findById($userID);
32895
32896            # validate user 
32897            if ($userData) {
32898                $userData = $userData['User'];
32899
32900                # Step 2 : prepare to create payment transaction
32901                $userTable = new UserTable($userData);
32902                $membershipTypeIndex = $userTable->getMembershipTypeIndex();
32903
32904                # fetch the plan details
32905                $logFileName = 'card_reregister';
32906
32907                // get free trial payment data
32908                $planData = $this->PaymentPlanPrice->getPaymentData(array(
32909                    'currencyCode' => $userData['currency_code'],
32910                    'paymentPlanId' => $plan_id,
32911                    'logFileName' => $logFileName
32912                ));
32913
32914                if (!$planData) {
32915                    return $result;
32916                }
32917
32918                $userData['price_id'] = $planData['priceId'];
32919                $userData['payment_plan_id'] = $planData['paymentPlanId'];
32920                $userData['statusBefore'] = $membershipTypes[$membershipTypeIndex];
32921                $userData['statusAfter'] = $statusAfter;
32922                $userData['paymentAmount'] = $planData['amount'];
32923
32924                if ($isNewRegister && $studentDiscountOptionData) {
32925                    $planData['amount'] = $userData['paymentAmount'] = 0;
32926                    $userData['discountOption'] = $studentDiscountOptionData;
32927                    $userData['userRegister'] = true;
32928                }
32929
32930                # Step 3  create payment transaction
32931                $pt = $this->createPaymentTransaction($formType, $userData);
32932
32933                if ($pt) {
32934                    # return the payment hash and the amount
32935                    $result['payment_hash'] = $pt['payment_hash'];
32936                    $result['payment_monthly_amount'] = $planData['amount'];
32937                }
32938            }
32939        }
32940
32941        return $result;
32942    }
32943    /**
32944     * @api {post} /payment/applyCouponPayment applyCouponPayment()
32945     * @apiName applyCouponPayment
32946     * @apiGroup Payment
32947     * @apiDescription This endpoint is used to apply coupon payment.
32948     * 
32949     * @apiBody {String} token User token.
32950     * @apiBody {String} totalAmount Total amount of the payment.
32951     * @apiBody {String} couponAmount Coupon amount to be used.
32952     * @apiBody {String} [isUseAllCoupon] If set to 1, all available coupon points will be used.
32953     * 
32954     * @apiSuccess {Boolean} success Indicates if the coupon was applied successfully.
32955     * @apiSuccess {Number} totalCouponUsed The total amount of coupons used.
32956     * @apiSuccess {String} totalCouponUsedFomat The formatted total amount of coupons used.
32957     * @apiSuccess {String} availableCouponPoints The formatted available coupon points.
32958     * @apiSuccess {String} totalAmountFormat The formatted total amount after applying the coupon.
32959     * @apiSuccess {Number} totalAmount The total amount after applying the coupon.
32960     * 
32961     * @apiError {Boolean} success Indicates if the coupon was applied successfully.
32962     * 
32963     * @apiSuccessExample Success Response:
32964     * {
32965     *   "success": true,
32966     *   "totalCouponUsed": 100,
32967     *   "totalCouponUsedFomat": "100",
32968     *   "availableCouponPoints": "50",
32969     *   "totalAmountFormat": "150",
32970     *   "totalAmount": 150
32971     * }
32972     * 
32973     * @apiErrorExample Error Response:
32974     * {
32975     *   "success": false
32976     * }
32977     */
32978    public function applyCouponPayment() {
32979        $this->layout = false;
32980        $this->autoRender = false;
32981        $response = ['success' => false];
32982
32983        if ($this->request->is('post')) {
32984            $data = $this->request->data;
32985            $apiToken = !empty($this->request->query['token']) ? $this->request->query['token'] : null;
32986
32987            $user_id = null;
32988            $user_currency_code = null;
32989            if (!empty($this->sharedUserData['User']['id'])) {
32990                $user_id = $this->sharedUserData['User']['id'];
32991                $user_currency_code = $this->sharedUserData['User']['currency_code'];
32992            } else if (!empty($apiToken)) {
32993                $userData = $this->User->getUserDataByApiToken($apiToken);
32994
32995                if (!empty($userData['User']['id'])) {
32996                    $user_id = $userData['User']['id'];
32997                    $user_currency_code = $userData['User']['currency_code'];
32998                }
32999            }
33000            
33001            // available coupon points
33002            $availableCouponPoints = $this->UsersCouponV1->availableCoupon($user_id);
33003
33004            if ($availableCouponPoints > 0) {
33005                $couponData = $this->Session->read('apply_coupon_usage_data');
33006
33007                if (empty($couponData)) {
33008                    // Get Coupon Used
33009                    $totalCouponUsedParams = [
33010                        'userId'            => $user_id,
33011                        'kbn'                => Configure::read('coupon_kbn.monthly_settlement')
33012                    ];
33013                    $couponRequestData = $this->UsersCouponV1->getCouponUseRequest($totalCouponUsedParams);
33014                    $totalCouponUsed = !empty($couponRequestData['amount']) ? $couponRequestData['amount'] : 0;
33015
33016                    $couponData = [
33017                        'previousUsedCoupon' => $totalCouponUsed,
33018                        'logFileName' => 'heync',
33019                        'availableCouponPoints' => $availableCouponPoints
33020                    ];
33021                }
33022
33023                $couponData['userId'] = $user_id;
33024                $couponData['paymentAmount'] = !empty($data['totalAmount']) ? $data['totalAmount'] : 0;
33025
33026                if (isset($data['isUseAllCoupon']) && $data['isUseAllCoupon'] == 1) {
33027                    if (isset($data['totalAmount']) && $data['totalAmount'] > 0) {
33028                        $couponData['kbn'] = Configure::read('coupon_kbn.monthly_settlement'); // monthly charge kbn
33029
33030                        if ($couponData['availableCouponPoints'] >= $data['totalAmount']) {
33031                            $couponData['useCouponAmount'] = $data['totalAmount'];
33032                        } else {
33033                            $couponData['useCouponAmount'] = $couponData['availableCouponPoints'];
33034                        }
33035
33036                        $response['success'] = true;
33037                    }
33038                } else {
33039                    // use selected coupon amount
33040                    if (isset($data['couponAmount']) && $data['couponAmount'] > 0) {
33041                        $couponData['kbn'] = Configure::read('coupon_kbn.monthly_settlement'); // monthly charge kbn
33042                        
33043                        // apply coupon amount
33044                        if ($data['couponAmount'] > $availableCouponPoints) {
33045                            $couponData['useCouponAmount'] = $availableCouponPoints;
33046                        } else {
33047                            $couponData['useCouponAmount'] = $data['couponAmount'];
33048                        }
33049                        
33050                        // validate if the paymentAmount is greater than the coupon amount
33051                        if ($couponData['paymentAmount'] < $couponData['useCouponAmount']) {
33052                            $couponData['useCouponAmount'] = $couponData['paymentAmount'];
33053                        }
33054
33055                        $response['success'] = true;
33056                    }
33057                }
33058            }
33059        }
33060
33061        if ($response['success'] == true) {
33062            $this->Session->write('apply_coupon_usage_data',$couponData);
33063
33064            // worldpay payment using coupon settlement
33065            if ($wpCouponSettlement = $this->Session->read('wp_coupon_settlement_payment')) {
33066
33067                if (isset($wpCouponSettlement['payment_hash']) && isset($wpCouponSettlement['payment_amount'])) {
33068                    $paymentAmount = $wpCouponSettlement['payment_amount'];
33069
33070                    if (isset($couponData['useCouponAmount']) && $couponData['useCouponAmount'] > 0 && $paymentAmount > 0) {
33071                        if ($paymentAmount >= $couponData['useCouponAmount']) {
33072                            $paymentAmount -= $couponData['useCouponAmount'];
33073                        } else {
33074                            $paymentAmount = 0;
33075                        }
33076                    }
33077
33078                    $currencyExponents = Configure::read('worldpay.currency_exponents');
33079                    $exponent = $currencyExponents[$user_currency_code];
33080
33081                    // get total amount with checking currency exponent
33082                    $totalAmountArr = myTools::wpGetAmount($exponent, $paymentAmount);
33083                    $wpPaymentAmount = $totalAmountArr['wpAmount'];
33084
33085                    $paymentParamsData = [
33086                        'couponUseSettlement' => $couponData,
33087                        'wpPaymentAmount' => $wpPaymentAmount,
33088                        'paymentAmount' => $paymentAmount
33089                    ];
33090
33091                    $this->PaymentTransaction->updatePaymentParams(array('paymentHash' => $wpCouponSettlement['payment_hash'], 'updateData' => $paymentParamsData));
33092                }
33093            }
33094
33095            $response['totalCouponUsed'] = $couponData['previousUsedCoupon'] + $couponData['useCouponAmount'];
33096            $response['totalCouponUsedFomat'] = myTools::formatAmount($couponData['previousUsedCoupon'] + $couponData['useCouponAmount']);
33097            $response['availableCouponPoints'] = myTools::formatAmount($couponData['availableCouponPoints'] - $couponData['useCouponAmount']);
33098            $response['totalAmountFormat'] = myTools::formatAmount($couponData['paymentAmount'] - $couponData['useCouponAmount']);
33099            $response['totalAmount'] = $couponData['paymentAmount'] - $couponData['useCouponAmount'];
33100        }
33101
33102        return json_encode($response);
33103    }
33104
33105    public function setCouponUseData($user_id = null, $currency_code = 'JPY') {
33106        $couponSymbol = myTools::getNewCurrencySymbol($currency_code);
33107        $availableCouponPoints = $this->UsersCouponV1->availableCoupon($user_id);
33108
33109        // Get Coupon Used
33110        $totalCouponUsedParams = [
33111            'userId'            => $user_id,
33112            'kbn'                => Configure::read('coupon_kbn.monthly_settlement')
33113        ];
33114        
33115        $couponRequestData = $this->UsersCouponV1->getCouponUseRequest($totalCouponUsedParams);
33116        $totalCouponUsed = !empty($couponRequestData['amount']) ? $couponRequestData['amount'] : 0;
33117        
33118        if ($totalCouponUsed) {
33119            // confiscate the coupon pending request when student is re-enrolled
33120            $res_confiscate = $this->UsersCouponV1->confiscateAllCoupon(array(
33121                'userId' => $user_id,
33122                'action_type' => 1 // only the pending request will be confiscated
33123            ));
33124            $totalCouponUsed = 0;
33125        }
33126
33127        $couponData = [
33128            'previousUsedCoupon' => $totalCouponUsed,
33129            'availableCouponPoints' => $availableCouponPoints
33130        ];
33131
33132        $readSkipConfirmation = $this->Session->read('credit_skip_to_confirmation');
33133
33134        if (!$this->request->is('post') && !$readSkipConfirmation) {
33135            $this->Session->write('apply_coupon_usage_data', $couponData);
33136        }
33137        
33138        $this->set('couponSymbol',$couponSymbol);
33139        $this->set('availableCouponPoints',$availableCouponPoints);
33140        $this->set('totalCouponUsed',$totalCouponUsed);
33141    }
33142    // NJ-32737-end
33143    /**
33144     * @api {post} /payment/paypal-webhook paypalWebhook()
33145     * @apiName paypalWebhook
33146     * @apiGroup Payment
33147     * @apiDescription This endpoint is used to handle paypal webhook notification.
33148     * 
33149     * @apiBody {String} id The unique identifier for the webhook event
33150     * @apiBody {String} event_version The version of the event
33151     * @apiBody {String} create_time The time the event was created
33152     * @apiBody {String} resource_type The type of resource associated with the event
33153     * @apiBody {String} event_type The type of event that occurred
33154     * @apiBody {String} summary A summary of the event
33155     * @apiBody {Object} resource The resource data associated with the event
33156     * @apiBody {String} resource.id The billing agreement ID
33157     * @apiBody {String} resource.state The state of the billing agreement
33158     * @apiBody {String} resource.description The description of the billing agreement
33159     * @apiBody {String} resource.start_date The start date of the billing agreement
33160     * @apiBody {Object} resource.payer The payer information
33161     * @apiBody {String} resource.payer.payment_method The payment method used
33162     * @apiBody {String} resource.payer.status The status of the payer
33163     * @apiBody {Object} resource.payer.payer_info The payer's information
33164     * @apiBody {String} resource.payer.payer_info.email The payer's email
33165     * @apiBody {String} resource.payer.payer_info.payer_id The payer's ID
33166     * @apiBody {String} resource.payer.payer_info.first_name The payer's first name
33167     * @apiBody {String} resource.payer.payer_info.last_name The payer's last name
33168     * @apiBody {Object} resource.plan The plan information
33169     * @apiBody {Object[]} resource.plan.payment_definitions The payment definitions
33170     * @apiBody {String} resource.plan.payment_definitions.type The type of payment
33171     * @apiBody {String} resource.plan.payment_definitions.frequency The frequency of the payment
33172     * @apiBody {Object} resource.plan.payment_definitions.amount The amount of the payment
33173     * @apiBody {String} resource.plan.payment_definitions.amount.currency The currency of the payment
33174     * @apiBody {String} resource.plan.payment_definitions.amount.value The value of the payment
33175     * @apiBody {Object[]} links Hypermedia links related to the event
33176     * @apiBody {String} links.href The URL of the link
33177     * @apiBody {String} links.rel The relationship of the link
33178     * @apiBody {String} links.method The HTTP method to use for the link
33179     * 
33180     * @apiSuccess {Number} statusCode 200 If webhook notification is successful
33181     * 
33182     * @apiError {Number} statusCode 400 Bad Request if headers or webhook data are invalid
33183     * @apiError {Number} statusCode 400 Bad Request if webhook validation fails
33184     * @apiError {Number} statusCode 400 Bad Request if billing agreement ID is missing
33185     * @apiError {Number} statusCode 500 Internal Server Error if user data does not exist
33186     * 
33187     * @apiExample {json} Example usage:
33188     * {
33189     *       "id": "WH-1234-5678-9012-3456",
33190     *       "event_version": "1.0",
33191     *       "create_time": "2023-10-01T12:34:56Z",
33192     *       "resource_type": "billing_agreement",
33193     *       "event_type": "BILLING_AGREEMENTS.AGREEMENT.CANCELLED",
33194     *       "summary": "A billing agreement was cancelled",
33195     *       "resource": {
33196     *             "id": "I-BW452GLLEP1G",
33197     *             "state": "Cancelled",
33198     *             "description": "Billing Agreement",
33199     *             "start_date": "2023-10-01T00:00:00Z",
33200     *             "payer": {
33201     *               "payment_method": "paypal",
33202     *               "status": "verified",
33203     *               "payer_info": {
33204     *                     "email": "payer@example.com",
33205     *                     "payer_id": "123456789",
33206     *                     "first_name": "John",
33207     *                     "last_name": "Doe"
33208     *               }
33209     *             },
33210     *             "plan": {
33211     *               "payment_definitions": [
33212     *                     {
33213     *                   "type": "REGULAR",
33214     *                   "frequency": "Month",
33215     *                   "amount": {
33216     *                         "currency": "USD",
33217     *                         "value": "10.00"
33218     *                    }
33219     *                  }
33220     *               ]
33221     *                 }
33222     *           },
33223     *       "links": [
33224     *        {
33225     *           "href": "https://api.paypal.com/v1/notifications/webhooks-events/WH-1234-5678-9012-3456",
33226     *           "rel": "self",
33227     *           "method": "GET"
33228     *        }
33229     *       ]
33230     * }
33231     * 
33232     * @apiSuccessExample Success Response:
33233     * Returns status code 200 
33234     * 
33235     * @apiErrorExample Error Response if headers or webhook data are invalid:
33236     * Returns status code 400
33237     * 
33238     * @apiErrorExample Error Response if webhook validation fails:
33239     * Returns status code 400
33240     * 
33241     * @apiErrorExample Error Response if billing agreement ID is missing:
33242     * Returns status code 400
33243     * 
33244     * @apiErrorExample Error Response if user data does not exist:
33245     * Returns status code 500
33246     */
33247    public function paypalWebhook() {
33248        $this->autoLayout = false;
33249        $this->autoRender = false;
33250
33251        $headers = getallheaders();
33252        $webhookData = $this->request->data;
33253
33254        $this->log(__METHOD__ . "PAYPAL WEBHOOK - headers: " . json_encode($headers), 'paypal_debug');
33255        $this->log(__METHOD__ . "PAYPAL WEBHOOK - body: " . json_encode($webhookData), 'paypal_debug');
33256
33257        if (empty($headers) || empty($webhookData)) {
33258            $this->log(__METHOD__ . "- Invalid headers", 'paypal_debug');
33259            return $this->response->statusCode(400);
33260        }
33261
33262        if (!class_exists('PayPal')) {
33263            App::import('Lib', 'PayPal');
33264        }
33265
33266        $paypal = new Paypal();
33267        
33268        $isValidWebhook = $paypal->validatePaypalNotification(array('headers' => $headers, 'data' => $webhookData));
33269        //-- return status code 400 if validate webhook failed
33270        if (!$isValidWebhook) { 
33271            $this->log(__METHOD__ . "- Validate webhook failed", 'paypal_debug');
33272            return $this->response->statusCode(400); 
33273        } 
33274
33275        $billingAgreementId = isset($webhookData['resource']['id']) ? $webhookData['resource']['id'] : null;
33276        if (empty($billingAgreementId)) { 
33277            $this->log(__METHOD__ . "- Billing agreement ID is null", 'paypal_debug');
33278            return $this->response->statusCode(400); 
33279        } 
33280
33281        $this->User->openDBReplica();
33282        $users = $this->User->find('all', array(
33283            'fields' => array(
33284                'User.id',
33285                'User.paypal_billing_agreement_id',
33286                'User.payment_plan_id',
33287                'User.memo',
33288                'User.email',
33289                'User.native_language2'
33290            ),
33291            'conditions' => array('User.paypal_billing_agreement_id' => $billingAgreementId),
33292            'recursive' => -1
33293        ));
33294        $this->User->closeDBReplica();
33295
33296        if (empty($users)) {
33297            $this->log(__METHOD__ . "- User data does not exist", 'paypal_debug');
33298            return $this->response->statusCode(500);
33299        }
33300
33301        // handle webhook notification
33302        switch($webhookData['event_type']) {
33303            // handle cancelled subscription
33304            case 'BILLING_AGREEMENTS.AGREEMENT.CANCELLED': 
33305                $freePlans = array(
33306                    Configure::read('payment_plans.free_trial'),
33307                    Configure::read('payment_plans.free_trial_apple'),
33308                    Configure::read('payment_plans.free_trial_google'),
33309                    Configure::read('payment_plans.weekly_free_trial_apple'),
33310                    Configure::read('payment_plans.weekly_free_trial_google'),
33311                    Configure::read('payment_plans.free_trial_family'),
33312                    Configure::read('payment_plans.studysapuri_biz_free'),
33313                    Configure::read('payment_plans.studysapuri_everyday_free'),
33314                    Configure::read('payment_plans.light_plan_free')
33315                );
33316
33317                foreach($users as $user) {
33318                    // check if user is currently in free trial -> update membership to free
33319                    $paymentPlanID = $user['User']['payment_plan_id'];
33320                    if (in_array($paymentPlanID, $freePlans)) {
33321                        // update main user
33322                        $memo = 'Change status to free from Paypal webhook';
33323                        $userObj = new UserTable($user['User']);
33324                        $native_lang = $userObj->native_language2;
33325
33326                        if ($this->User->updateStatusToFree($userObj, $memo)) {
33327                            if ( 
33328                                $paymentPlanID == Configure::read('payment_plans.free_trial') ||
33329                                $paymentPlanID == Configure::read('payment_plans.light_plan_free')
33330                            ) {
33331                                // send cancellation completion mail
33332                                $userDeactivationFlag = 1;
33333                                $userData['User']['native_language2'] = $native_lang;
33334                                $mail_id = Configure::read('site_in_mail.student_deactivation_complete');
33335                                myMailer::sendTemplateMail($mail_id, $user['User']['email'], $user['User'], array(), 'User', $userDeactivationFlag);
33336                            }
33337                            $this->log(__METHOD__ . '- USER: ' . $userObj->id . ' ' . $memo, 'paypal_debug');
33338                        } else {
33339                            $this->log(__METHOD__ . '- Failed to change user status to free', 'paypal_debug');
33340                        }
33341
33342                        // also update children users if existing
33343                        $childList = $this->User->getChildsDetail($user['User']['id']);
33344                        if(!empty($childList)) {
33345                            foreach($childList as $child) {
33346                                $childUserObj = new UserTable($child['User']);
33347                                if ($this->User->updateStatusToFree($childUserObj, $memo)) {
33348                                    $this->log(__METHOD__ . '- CHILD USER: ' . $childUserObj->id . ' ' . $memo, 'paypal_debug');
33349                                } else {
33350                                    $this->log(__METHOD__ . '- Failed to change child user status to free', 'paypal_debug');
33351                                }
33352                            }
33353                        }
33354
33355                    }
33356                }
33357
33358                break;
33359        }
33360
33361        return $this->response->statusCode(200);
33362    }
33363
33364    /**
33365     * @api {post} /payment/createChocottoPlanTransaction/:userId/:formType/:isNewRegister createChocottoPlanTransaction()
33366     * @apiName createChocottoPlanTransaction
33367     * @apiGroup Payment
33368     * @apiDescription This endpoint is used to create payment transaction for chocotto plan.
33369     * 
33370     * @apiParam {Number} userId The user ID. null if user data does not exist.
33371     * @apiParam {Number} formType The form type. null if form type is invalid.
33372     * @apiParam {Number} isNewRegister The flag to check if user is newly registered. null if flag is invalid.
33373     * 
33374     * @apiSuccess {String} payment_hash The payment hash.
33375     * @apiSuccess {Number} payment_monthly_amount The monthly payment amount.
33376     * 
33377     * @apiError {String} Array returns an empty array
33378     * 
33379     * @apiSuccess {json} Example usage:
33380     * {
33381     *      "payment_hash": "123456789",
33382     *         "payment_monthly_amount": 1000
33383     * }
33384     * 
33385     * @apiErrorExample {json} Error Response:
33386     * {}    
33387     */
33388    public function createChocottoPlanTransaction($params = []){
33389        $userID = isset($params['userId']) ? $params['userId'] : null;
33390        $formType = isset($params['formType']) ? $params['formType'] : null;
33391        $isNewRegister = isset($params['isNewRegister']) ? $params['isNewRegister'] : false;
33392
33393        $result = array();
33394
33395        if ($userID) {
33396            $plan_id = null;
33397            $statusAfter = null;
33398            $membershipTypes = UserTable::getEngMembershipTypeData();
33399
33400            # Step 0 : set the correct form type
33401            if ($isNewRegister) {
33402                # set the correct form type for newly register
33403                $formType = Configure::read('payment_credit_chocotto_free');
33404                $plan_id = Configure::read('payment_plans.free_trial_chocotto');
33405                $statusAfter = $membershipTypes[Configure::read('membership_type_chocotto_plan_free')];
33406            }else{
33407                $plan_id = Configure::read('payment_plans.chocotto_plan');
33408                $statusAfter = $membershipTypes[Configure::read('membership_type_chocotto_plan_paid')];
33409
33410                # set the correct form type for charge 
33411                if ($formType == Configure::read('payment_credit_force_charge')) {
33412                    $formType = Configure::read('payment_credit_chocotto_force_charge');
33413                }
33414            }
33415
33416            # Step 1 fetch user data 
33417            $userData = $this->User->find('first', [
33418                'conditions' => ['User.id' => $userID],
33419                'recursive' => -1
33420            ]);
33421
33422            # validate user 
33423            if ($userData) {
33424                $userData = $userData['User'];
33425
33426                # Step 2 : prepare to create payment transaction
33427                $userTable = new UserTable($userData);
33428                $membershipTypeIndex = $userTable->getMembershipTypeIndex();
33429
33430                # fetch the plan details
33431                $logFileName = 'card_reregister';
33432
33433                // get free trial payment data
33434                $planData = $this->PaymentPlanPrice->getPaymentData(array(
33435                    'currencyCode' => $userData['currency_code'],
33436                    'paymentPlanId' => $plan_id,
33437                    'logFileName' => $logFileName
33438                ));
33439
33440                if (!$planData) {
33441                    return $result;
33442                }
33443
33444                $userData['price_id'] = $planData['priceId'];
33445                $userData['payment_plan_id'] = $planData['paymentPlanId'];
33446                $userData['statusBefore'] = $membershipTypes[$membershipTypeIndex];
33447                $userData['statusAfter'] = $statusAfter;
33448                $userData['paymentAmount'] = $planData['amount'];
33449
33450                if ($isNewRegister) {
33451                    $planData['amount'] = $userData['paymentAmount'] = 0;
33452                    $userData['userRegister'] = true;
33453                }
33454
33455                # Step 3  create payment transaction
33456                $pt = $this->createPaymentTransaction($formType, $userData);
33457
33458                if ($pt) {
33459                    # return the payment hash and the amount
33460                    $result['payment_hash'] = $pt['payment_hash'];
33461                    $result['payment_monthly_amount'] = $planData['amount'];
33462                }
33463            }
33464        }
33465
33466        return $result;
33467    }    
33468
33469
33470    // NJ-23803: Official Webhook from Stripe
33471    // Needs Stripe Signature Verification
33472    public function stripepay() {
33473        $this->autoLayout = false;
33474        $this->autoRender = false;
33475
33476        $this->response->type('application/json');
33477        $this->response->charset('UTF-8');
33478    
33479        $payload = mb_convert_encoding($this->request->input(), 'UTF-8', 'auto');
33480        $this->log(__METHOD__ . ' Stripe Payload: ' . $payload, 'monthly_payment');
33481    
33482        if (!class_exists('Stripe')) {
33483            App::import('Lib', 'Stripe');
33484        }
33485    
33486        $stripe = new Stripe();
33487        if (!$stripe->verifyStripeSignature($payload)) {
33488            $this->log(__METHOD__ . ' Error: Invalid Stripe signature: ' . $payload, 'monthly_payment');
33489            throw new BadRequestException('Invalid signature');
33490        }
33491    
33492        $event = json_decode($payload, true);
33493        if (json_last_error() !== JSON_ERROR_NONE) {
33494            $this->log(__METHOD__ . ' JSON decoding error: ' . json_last_error_msg(), 'monthly_payment');
33495            throw new BadRequestException('Invalid JSON');
33496        }
33497    
33498        switch ($event['type']) {
33499            case 'payment_intent.payment_failed':
33500                $this->log(__METHOD__ . ' Stripe payment failed', 'monthly_payment');
33501                // Handle payment failed
33502                $this->handleStripePaymentResult($event);
33503                break;
33504    
33505            case 'payment_intent.succeeded':
33506                $this->log(__METHOD__ . ' Stripe payment success', 'monthly_payment');
33507                // Handle successful payment
33508                $this->handleStripePaymentResult($event);
33509                break;
33510            
33511            case 'setup_intent.succeeded':
33512                $this->log(__METHOD__ . ' Stripe card authentication success', 'monthly_payment');
33513                // Handle successful card authenticaton
33514                $this->handleStripePaymentResult($event);
33515                break;
33516    
33517            default:
33518                $this->log(__METHOD__ . ' Received unknown event type ' . $event['type'], 'monthly_payment');
33519        }
33520    
33521        // Set the status code and send the response
33522        $this->response->statusCode(200);
33523        $this->response->send();
33524    }
33525
33526    // NJ-23803: Manually Triggered Webhook from CRON
33527    public function stripepay_manual() {
33528        $this->autoLayout = false;
33529        $this->autoRender = false;
33530
33531        $data = $this->request->query;
33532        $this->log(__METHOD__ . ' Stripe Manual Kickback Payload: ' . json_encode($data), 'monthly_payment');
33533        $this->handleStripePaymentResult($data);
33534
33535    }
33536
33537
33538    private function handleStripePaymentResult ($params = array()) {
33539
33540        $data = isset($params['data']['object']) ? $params['data']['object'] : array();
33541        if (empty($data)) {
33542            $this->log(__METHOD__ . ' Stripe Object is empty ', 'monthly_payment');
33543            return;
33544        }
33545
33546        $paymentHash = isset($data['metadata']['sendpoint']) ? trim($data['metadata']['sendpoint']) : null;
33547        $data['ordd'] = $paymentHash;
33548        if (empty($paymentHash)) {
33549            $this->log(__METHOD__ . ' stripe.error.no_payment_hash ', 'monthly_payment');
33550            return;
33551        }
33552
33553        $data['sendid'] = isset($data['metadata']['sendid']) ? $data['metadata']['sendid'] : null;
33554        $moneyAmt = isset($data['metadata']['money']) ? $data['metadata']['money'] : 0;
33555        if (!isset($data['metadata']['money']) && isset($data['amount'])) {
33556            $moneyAmt = $data['amount'];
33557        }
33558        $data['money'] = $moneyAmt;
33559        
33560        if (empty($data['sendid'])) {
33561            $this->log(__METHOD__ . ' stripe.error.no_payment_hash ', 'monthly_payment');
33562            return;
33563        }
33564
33565        $this->sendStripeResponseSlackMessage(array(
33566            'paymentHash' => $paymentHash,
33567            'response' => $data,
33568            'userId' => $data['sendid'],
33569            'action' => 'Stripe Payment Kickback'
33570        ));
33571
33572        $this->loadModel("UsersPoint");
33573        $this->loadModel("Payment");
33574        $this->loadModel("ContinuationCampaign");
33575
33576            
33577        # set variables
33578        $telecom_zeus_convert = false;
33579        $formType = Configure::read('payment_credit_default');
33580        $platform = Configure::read('platform.pclp');
33581        $receivablePayment = $liveLessonReceivable = 0;
33582        $dateNow = date("Y-m-d H:i:s");
33583        $appreciationFlg = 0;
33584        $tipAmount = null;
33585
33586        // prevent switching to replicas inside kickback
33587        $this->PaymentTransaction->setOverrideConnectFlg(true);
33588
33589        // get payment transaction
33590        $ptData = $this->PaymentTransaction->getWPPaymentTransaction($paymentHash);
33591
33592        // if pending payment transaction does not exist try to remove condition to check if has failed transation to override it
33593        if (!$ptData) {
33594            // override the last transaction
33595            $ptData = $this->PaymentTransaction->find('first', array(
33596                'fields' => array(
33597                    'id',
33598                    'user_id',
33599                    'password',
33600                    'payment_params'
33601                ),
33602                'conditions' => array(
33603                    'payment_hash' => $paymentHash
33604                ),
33605                'recursive' => -1
33606            ));
33607
33608            if ($ptData) {
33609                $ptData = $ptData['PaymentTransaction'];
33610            }
33611        }
33612
33613        // do nothing if payment transaction (payment hash and status = 0) does not exist.
33614        if (!$ptData) {
33615            $this->log(__METHOD__ . ' Payment transaction status 0 does not exist. ' . json_encode($data), 'monthly_payment');
33616            // Send to slack only if money is greater than 0
33617            if (isset($data['money']) && $data['money'] > 0) {
33618                $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, 0, 'Payment transaction status 0 does not exist', $data);
33619            }
33620            return ;
33621        }
33622
33623        // decode payment params to array
33624        $ptPaymentParams = json_decode($ptData['payment_params'], true);
33625        $familyId = isset($ptPaymentParams['familyId']) ? $ptPaymentParams['familyId'] : null;
33626        $userId = $familyId ? $familyId : $data['sendid'];
33627        $cardExpirationDate = isset($data['cardexpirationdate']) ? $data['cardexpirationdate'] : null;
33628        $logFileName = isset($ptPaymentParams['logFileName']) ? $ptPaymentParams['logFileName'] : 'monthly_payment';
33629        $basicFee = isset($ptPaymentParams['basicFee']) ? $ptPaymentParams['basicFee'] : 0;
33630        $lessonFee = isset($ptPaymentParams['lessonFee']) ? $ptPaymentParams['lessonFee'] : 0;
33631        $lessonFeeDateStarted = isset($ptPaymentParams['lessonFeeDateStarted']) ? $ptPaymentParams['lessonFeeDateStarted'] : null;
33632        $ptId = $ptData['id'];
33633        $stripePaymentMethod = isset($data['payment_method']) ? $data['payment_method'] : null;
33634        $stripeCustomerID = isset($data['customer']) ? $data['customer'] : null;
33635        
33636        //remove from paying users memcache
33637        UserTable::removePayingUserFromMemcache($userId);
33638
33639        # check the source of the payment
33640        if (isset($ptPaymentParams['formType'])) {
33641            $formType = $ptPaymentParams['formType'];
33642        }
33643
33644        // prevent switching to replicas inside kickback
33645        $this->Payment->setOverrideConnectFlg(true);
33646        
33647        $monthlyPaymentExist = $this->Payment->find('count', array(
33648            'conditions' => array(
33649                'Payment.user_id' => $userId,
33650                'Payment.ordd' => $data['ordd'],
33651                'Payment.card_company' => Configure::read('card_company.stripe'),
33652                'Payment.form_type' => $formType
33653            )
33654        ));
33655        
33656        // NC-4036: do nothing if stripe user and monthly payment transaction (ordd) already exist.
33657        if ($monthlyPaymentExist) {
33658            $this->log(__METHOD__ . ' Payments data already exist. ' . json_encode($data), $logFileName);
33659            $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Payments data already exist', $data);
33660            return ;
33661        }
33662
33663        // NC-8600: if family is withdrawn
33664        if ($formType == Configure::read('payment_credit_family_monthly_payment') && $this->memcache->get('deactivated-user-'.$userId)) {
33665            $this->log(__METHOD__ . ' User is withdrawn. ' . json_encode($data), 'monthly_payment');
33666            $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'User is withdrawn', $data);
33667            return;
33668        }
33669        
33670        // save settlement history for tracking
33671        if (!SettlementHistoryTable::add(array(
33672                'userId' => $userId,
33673                'params' => json_encode($data),
33674                'createdIp' => $dateNow,
33675                'modifiedIp' => $dateNow
33676            )
33677        )) {
33678            $this->log(__METHOD__ . ' Failed to save stripepay kickback data in settlement history. ' . json_encode($data), $logFileName);
33679            $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save zeuspay kickback data in settlement history', $data);
33680            return;
33681        }
33682
33683        # append data parameters
33684        $data += array(
33685                'ip' => isset($ptPaymentParams['remoteAddress']) ? $ptPaymentParams['remoteAddress'] : null,
33686                'user_id' => $userId,
33687                'created' => $dateNow,
33688                'modified' => $dateNow,
33689        );
33690
33691        # check if user exists, and remove any bound models
33692        $userData = $this->User->find("first",array("conditions" =>array("User.id"=>$userId), "recursive" => -1));
33693        if (!$userData) {
33694            $this->log(__METHOD__ . ' User id does not exist. ' . json_encode($userId) . ' -- ' . json_encode($data), $logFileName);
33695            $data['error_code'] = Configure::read('zeus.error.no_user');
33696            $this->stripe_error_log_set($data, $ptPaymentParams);
33697            $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'User id does not exist', $data);
33698            return ;
33699        }
33700
33701        $card_company = isset($data['metadata']['card_company']) ? $data['metadata']['card_company'] : null;
33702        if (empty($card_company) && isset($userData['User']['card_company']) ) {
33703            $card_company = $userData['User']['card_company'];
33704        }
33705
33706        $membershipStatusIndex = UserTable::getStudentMembershipStatus($userId);
33707
33708
33709        # check if ordd is present
33710        if (isset($data['ordd']) === FALSE) {
33711            $data['ordd'] = NULL;
33712        }
33713
33714
33715        # check if payment transaction password exist
33716        $ptPassword = "";
33717        if (isset($ptData['password'])) {
33718            $ptPassword = $ptData['password'];
33719        }
33720
33721        # check if payment type is from payment plan or coin purchase or textbook purchase
33722        if (isset($ptPaymentParams['paymentType'])) {
33723            $paymentType = $ptPaymentParams['paymentType'];
33724        }
33725
33726        # check platform
33727        if (isset($ptPaymentParams['platform'])) {
33728            $platform = $ptPaymentParams['platform'];
33729        }
33730
33731        $paymentPlanId = isset($ptPaymentParams['paymentPlanId']) ? $ptPaymentParams['paymentPlanId'] : null;
33732        $priceId = isset($ptPaymentParams['priceId']) ? $ptPaymentParams['priceId'] : null;
33733        $currencyCode = isset($ptPaymentParams['currencyCode']) ? $ptPaymentParams['currencyCode'] : Configure::read('currency_jpy');
33734        $discounted_amount = isset($ptPaymentParams['discounted_amount']) ? $ptPaymentParams['discounted_amount'] : 0;
33735
33736        // if using coupon during force settlement
33737        if (!empty($ptPaymentParams['couponUseSettlement']) && !empty($ptPaymentParams['couponUseSettlement']['useCouponAmount']) && in_array($formType, Configure::read('allow_coupon.settlement_form_type'))) {
33738            $discounted_amount += $ptPaymentParams['couponUseSettlement']['useCouponAmount'];
33739        }
33740
33741        # NC-8194: check null payment_plan_id and price_id
33742        if (!$paymentPlanId || !$priceId) {
33743            if ( $userData['User']['payment_plan_id'] && $userData['User']['price_id']) {
33744                $paymentPlanId = $userData['User']['payment_plan_id'];
33745                $priceId = $userData['User']['price_id'];
33746            } else {
33747                $defPlan = $this->PaymentPlanPrice->getDefaultPlan($userData['User']);
33748                $paymentPlanId = $defPlan['paymentPlanId'];
33749                $priceId = $defPlan['priceId'];
33750            }
33751        }
33752
33753        # set data variables
33754        $data['paymentType'] = $paymentType;
33755        $data['formType'] = $formType;
33756
33757        // - NJ-18780 : check if lite plan user 
33758        // $isLitePlanUser = in_array($paymentPlanId, Configure::read('lite_payment_plans')) ? true : false;
33759
33760        $cronDateRun = isset($ptPaymentParams['cronDateRun']) ? $ptPaymentParams['cronDateRun'] : $dateNow;
33761
33762        $monthlyPayment = isset($data["money"]) ? $data["money"] : 0;
33763        $nativeOptionPayment = 0;
33764        $callanOptionPayment = 0;
33765
33766        
33767        // if monthly payment, retry or force charge
33768        // check if user has receivable payment
33769        if (in_array($formType, array(
33770            Configure::read('payment_credit_monthly_payment'),
33771            Configure::read('payment_credit_family_monthly_payment'),
33772            Configure::read('payment_credit_force_charge'),
33773            Configure::read('payment_credit_retry'),
33774            Configure::read('payment_credit_change')
33775        ))) {
33776
33777            $_allowChangePlan = true; // NJ-23803: assume true for Phase 1
33778
33779            // compute receivable payments
33780            $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userData['User']['id'], $cronDateRun);
33781
33782            // if has receivable payment
33783            // deduct said monthly settlement from the money sent to zeus
33784            if ($receivablePayment && $receivablePayment <= $data["money"] && $_allowChangePlan) {
33785                // deduct from monthly payment
33786                $monthlyPayment -= $receivablePayment;
33787            }
33788
33789            // if has native speaker payments
33790            // deduct
33791            if (isset($ptPaymentParams['nativeOptionPayment']) && $ptPaymentParams['nativeOptionPayment'] > 0 && $_allowChangePlan) {
33792                $nativeOptionPayment = $ptPaymentParams['nativeOptionPayment'];
33793                $monthlyPayment -= $nativeOptionPayment;
33794            }
33795
33796            // if has callan option payments
33797            // deduct
33798            if (isset($ptPaymentParams['callanOptionPayment']) && $ptPaymentParams['callanOptionPayment'] > 0 && $_allowChangePlan) {
33799                $callanOptionPayment = $ptPaymentParams['callanOptionPayment'];
33800                $monthlyPayment -= $callanOptionPayment;
33801            }
33802
33803            // compute appreciation receivable payments
33804            $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.appreciation'));
33805
33806            if ($appreciationReceivable && $appreciationReceivable <= $monthlyPayment) {
33807                $monthlyPayment -= $appreciationReceivable;
33808            }
33809
33810            // compute live lesson receivable payments
33811            $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userData['User']['id'], $cronDateRun, Configure::read('payment_element_type.live'));
33812
33813            if ($liveLessonReceivable && $liveLessonReceivable <= $monthlyPayment && $_allowChangePlan) {
33814                $monthlyPayment -= $liveLessonReceivable;
33815            }            
33816
33817            $ptPaymentParams['paymentAmount'] = $monthlyPayment;
33818        }
33819
33820        // Check receivables combine on `payment_credit_receivable` form type
33821        if( $formType == Configure::read('payment_credit_receivable') ) {
33822
33823            // compute appreciation receivable payments
33824            $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.appreciation'));
33825
33826            // deduct said receivable settlement from the money sent to zeus
33827            if ($appreciationReceivable && $appreciationReceivable <= $data["money"]) {
33828                // deduct from receivable payment
33829                $monthlyPayment -= $appreciationReceivable;
33830            }
33831
33832            // compute live receivable payments
33833            $liveLessonReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.live'));
33834
33835            // deduct said receivable settlement from the money sent to zeus
33836            if ($liveLessonReceivable && $liveLessonReceivable <= $data["money"]) {
33837                // deduct from receivable payment
33838                $monthlyPayment -= $liveLessonReceivable;
33839            }            
33840
33841            $ptPaymentParams['paymentAmount'] = $monthlyPayment;
33842        }
33843
33844        $kbResult = false;
33845        # check if the result is ok
33846        if ( myTools::checkStripePaymentResponse($data) ) {
33847            $kbResult = true;
33848            $this->log(__METHOD__ . 'result is ok', $logFileName);
33849
33850            # get current card company
33851            $currentCardCompany = is_null($userData['User']['card_company']) ? FALSE : intVal($userData['User']['card_company']);
33852
33853            # check if formType = 5
33854            if ($formType == Configure::read('payment_credit_coin_purchase') && isset($ptPaymentParams['coinPurchasePoints'])) {
33855                
33856                $coinPurchasePoints = intVal($ptPaymentParams['coinPurchasePoints']);
33857                $coinData = $this->UsersPoint->SET_charge_overseas_menue($coinPurchasePoints, $currencyCode);
33858
33859                // NC-5007 add to the user's existing coin
33860                $pcZeusPay = array(
33861                    'userId' => $userData['User']['id'],
33862                    'point' => $coinData['num_of_coin'] - $coinData['bonus_coin'],
33863                    'kbn' => 7,
33864                    'kbnType' => 1, // add coin
33865                    'coinType' => 1, // purchase coin
33866                    'coinFailMessage' => Configure::read('coin.failed.buy_coin'),
33867                    'device' => isset($ptPaymentParams['device']) ? $ptPaymentParams['device'] : null
33868                );
33869
33870                $scZeusPay = array(
33871                    'userId' => $userData['User']['id'],
33872                    'point' => $coinData['bonus_coin'],
33873                    'kbn' => 7,
33874                    'kbnType' => 1, // add coin
33875                    'coinType' => 2, // service coin
33876                    'coinFailMessage' => Configure::read('coin.failed.buy_coin'),
33877                    'device' => isset($ptPaymentParams['device']) ? $ptPaymentParams['device'] : null
33878                );
33879
33880                $pointParams = [$pcZeusPay, $scZeusPay];
33881
33882                if ( $pointParams ) {
33883                    foreach($pointParams as $key => $val) {
33884                        if (!$this->UsersPoint->performPointTransaction($val)) {
33885                            $this->log(__METHOD__ . ' Failed to add user point. ' . json_encode($val) . ' -- ' . json_encode($data), $logFileName);
33886                            $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to add user point', $data, $val);
33887                            return ;
33888                        }
33889                    }
33890                }
33891            }
33892
33893            // check if family plan and a coin purchase form type 
33894            if (
33895                $familyId 
33896                && in_array($formType, array(
33897                        Configure::read('payment_credit_coin_purchase'), 
33898                        Configure::read('payment_credit_textbook_purchase')
33899                    )
33900                )
33901            ) {
33902                // change reference id to parent id
33903                $referenceId = isset($data['sendid']) ? $data['sendid'] : 0;
33904            
33905            //IF Native option or callan option join payment and family
33906            } elseif(
33907                (
33908                    isset($ptPaymentParams['nativeOptionJoin']) 
33909                    && $ptPaymentParams['nativeOptionJoin'] 
33910                    && $familyId
33911                    && $ptPaymentParams['formType'] == Configure::read('payment_native_option_join')
33912                ) 
33913                ||
33914                (
33915                    isset($ptPaymentParams['callanOptionJoin']) 
33916                    && $ptPaymentParams['callanOptionJoin'] 
33917                    && $familyId
33918                    && $ptPaymentParams['formType'] == Configure::read('payment_callan_option_join')
33919                )
33920            ) {
33921                // change reference id to parent id
33922                $referenceId = isset($data['sendid']) ? $data['sendid'] : 0;
33923            } else {
33924                $referenceId = $userId;
33925            }
33926            
33927            $paymentData = array(
33928                'user_id' => $userId,
33929                'amount' => $monthlyPayment,
33930                'status' => 1,
33931                'reference_id' => $referenceId,
33932                'payment_transaction_password' => $ptPassword,
33933                'card_company' => $card_company,
33934                'param1' => json_encode($data),
33935                'form_type' => $formType,
33936                'ordd' => $data["ordd"],
33937                'transaction_code' => $paymentHash,
33938                'currency_id' => Configure::read('default.settlement_currency_id'), // set currency id to jpy
33939                'currency_code' => $currencyCode,
33940                'payment_id' => $paymentPlanId,
33941                'price_id' => $priceId,
33942                'payment_type' => $paymentType,
33943                'discounted_amount' => $discounted_amount
33944            );
33945
33946            $discountOption = isset($ptPaymentParams['discountOption']) ? $ptPaymentParams['discountOption'] : [];
33947            
33948            if (!empty($discountOption)) {
33949                $paymentData['discount_option_price_id'] = $discountOption['discount_option_price_id'];
33950            }
33951            
33952            // NJ-47740
33953            $discountType = 'monthly';
33954            if ($formType == Configure::read('payment_native_option_join')) {
33955                $discountType = 'native';
33956            } else if ($formType == Configure::read('payment_callan_option_join')) {
33957                $discountType = 'callan';
33958            } else if ($formType == Configure::read('payment_credit_coin_purchase')) {
33959                $discountType = 'coin';
33960            }
33961            
33962            $getCouponDiscounDetail = PaymentTable::getCouponDiscountRequestDetail($ptPaymentParams, $discountType);
33963            $paymentData['discounted_amount'] = !empty($getCouponDiscounDetail['discounted_amount']) ? $getCouponDiscounDetail['discounted_amount'] : 0;
33964            $paymentData['coupon_request_id'] = !empty($getCouponDiscounDetail['coupon_request_id']) ? $getCouponDiscounDetail['coupon_request_id'] : null;
33965            
33966            $forceSettlementWithCoupon  = false;
33967            // if using coupon during force settlement
33968            if (
33969                !empty($ptPaymentParams['couponUseSettlement']) && 
33970                !empty($ptPaymentParams['couponUseSettlement']['useCouponAmount']) && 
33971                in_array($formType, Configure::read('allow_coupon.settlement_form_type'))
33972            ) {
33973                // apply coupon use discount
33974                $couponData = $ptPaymentParams['couponUseSettlement'];
33975                $couponData['nextChargeDate'] = date('Y-m-d');
33976                $couponData['request_result'] = true;
33977
33978                $result_coupon_use = $this->UsersCouponV1->performCouponUse($couponData);
33979                $result_coupon_use = !empty($result_coupon_use) ? json_decode($result_coupon_use,true) : array();
33980                
33981                if (empty($result_coupon_use)) {
33982                    $this->log(__METHOD__ . ' Failed to used coupons.' . json_encode($couponData), $logFileName);
33983                    $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to used coupons.', $couponData, array_merge($_POST, $_SERVER));
33984                    return false;
33985                }
33986                
33987                $paymentData['discounted_amount'] = $ptPaymentParams['couponUseSettlement']['useCouponAmount'];
33988                $paymentData['coupon_request_id'] = isset($result_coupon_use['cgrp_id']) ? $result_coupon_use['cgrp_id'] : null;
33989                
33990                $forceSettlementWithCoupon = true;
33991            }
33992            
33993            // NC-10009 95% OFF new year campaign
33994            // During NC-10009 campaign 
33995            // Temporary -> Premiuim Plan Paid
33996            // Create two payment data for card authentication and for premium plan paid payment
33997            $newYear95percentOffCampaign = false;
33998            if (
33999                (isset($ptPaymentParams['campaign95percentOff']) && $ptPaymentParams['campaign95percentOff'])
34000                && (isset($ptPaymentParams['userRegister']) && $ptPaymentParams['userRegister'])
34001            ) 
34002            {
34003                $newYear95percentOffCampaign = true;
34004                $paymentDataForCardAuthentication = $paymentData;
34005                $paymentDataForCardAuthentication['amount'] = 0;
34006                $paymentDataForCardAuthentication['form_type'] = Configure::read('payment_credit_authentication');
34007                $paymentDataForCardAuthentication['payment_id'] = Configure::read('payment_plans.free_trial');
34008                $paymentDataForCardAuthentication['price_id'] = 1;
34009                // create new for card authentication payment
34010                $this->Payment->clear();
34011                $this->Payment->create();
34012                $this->Payment->set($paymentDataForCardAuthentication);
34013                $this->Payment->save();
34014            }
34015
34016            // NC-7029: save discount amount
34017            if ($discounted_amount > 0) {
34018                $paymentData['discounted_amount'] = $discounted_amount;
34019            }
34020
34021            //- check payment receivable with zero amount
34022            if (
34023                $formType == Configure::read('payment_credit_receivable') &&
34024                $monthlyPayment <= 0
34025            ) {
34026                //- skip saving
34027            } else {
34028                // create new payment
34029                $this->Payment->clear();
34030                $this->Payment->create();
34031                $this->Payment->set($paymentData);
34032                $savePaymentData = $this->Payment->save();
34033
34034                //update/add user`s settlement amount
34035                $this->User->updateUserPayments($paymentData);
34036                // check if payment was not saved
34037                if (!$this->Payment->save()) {
34038                    $this->log(__METHOD__ . ' Failed to save payment data. ' . json_encode($paymentData) . ' -- ' . json_encode($data), $logFileName);
34039                    $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data', $data, $paymentData);
34040
34041                    // if payment failed and has coupon grp id and its direct payment -> unconfirm coupon
34042                    if (
34043                        isset($paymentData['coupon_request_id']) && $paymentData['coupon_request_id'] &&
34044                        (
34045                            // the native or callan purchase with coupon use already has checker while processing the payment
34046                            // to ensure that payment errors are caught, place it here as well to make sure that the coupon is unconfirmed in case the page is refreshed while processing
34047                            in_array(
34048                                $formType, array(
34049                                    Configure::read('payment_native_option_join'),
34050                                    Configure::read('payment_callan_option_join'),
34051                                    Configure::read('payment_credit_coin_purchase')
34052                                )
34053                            ) ||
34054                            // force settlement with coupon
34055                            $forceSettlementWithCoupon
34056                        )
34057                    ) {
34058                        $couponKbn = Configure::read('coupon_kbn.coin_purchase'); // default
34059                        if ($formType == Configure::read('payment_native_option_join')) {
34060                            $couponKbn = Configure::read('coupon_kbn.native_option');
34061                        } else if ($formType == Configure::read('payment_callan_option_join')) {
34062                            $couponKbn = Configure::read('coupon_kbn.callan_option');
34063                        } else if ($forceSettlementWithCoupon) {
34064                            $couponKbn = Configure::read('coupon_kbn.monthly_settlement');
34065                        }
34066                        
34067                        $res_unconfirm = $this->UsersCouponV1->performCouponUnconfirm(array(
34068                            'grpId' => $paymentData['coupon_request_id'],
34069                            'userId' => $userId,
34070                            'kbn' => $couponKbn
34071                        ));
34072
34073                        if (empty($res_unconfirm)) {
34074                            $this->log(__METHOD__ . ' failed to perform coupon unconfirm.', $logFileName);
34075                        }
34076                    }
34077                    return ;
34078                }
34079
34080                // update payment details
34081                $updatePaymentDetailParams = array(
34082                    'currencyCode' => $paymentData['currency_code'],
34083                    'formType' => $paymentData['form_type'],
34084                    'paymentType' => $paymentData['payment_type'],
34085                    'amount' => $paymentData['amount'],
34086                    'discounted_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0,
34087                    'familyId' => $familyId,
34088                    'cronDateRun' => $cronDateRun,
34089                    'priceId' => $paymentData['price_id'],
34090                    'paymentPlanId' => $paymentData['payment_id'],
34091                    'user_id' => $paymentData['user_id'],
34092                    'coupon_use_request_id' => isset($paymentData['coupon_request_id']) ? $paymentData['coupon_request_id'] : null,
34093                    'coupon_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0
34094                );
34095                
34096                if (!empty($discountOption)) {
34097                    $updatePaymentDetailParams['discount_option_price_id'] = $discountOption['discount_option_price_id'];
34098                    $updatePaymentDetailParams['discount_option_amount'] = $discountOption['amount'];
34099                }
34100                $updatePaymentDetail = array(
34101                    'id' => $ptId,
34102                    'fields' => array(
34103                        'payment_details' => $updatePaymentDetailParams
34104                    )
34105                );
34106
34107                if (!$this->PaymentTransaction->updateWPPaymentTransaction($updatePaymentDetail)) {
34108                    $this->log(__METHOD__ . ' Failed to update payment details. ' . json_encode($updatePaymentDetail), $logFileName);
34109                }
34110
34111                // set payment_id
34112                $paymentSaveID = $this->Payment->id;
34113
34114                // NJ-47740
34115                if (!empty($paymentData['coupon_request_id']) && $paymentData['discounted_amount'] > 0) {
34116                    // confirm coupon use request for discount
34117                    $requestCouponConfirmData = array(
34118                        'grpId' => $paymentData['coupon_request_id'],
34119                        'paymentId' => $paymentSaveID
34120                    );
34121                    $result_confirm = $this->UsersCouponV1->performCouponConfirm($requestCouponConfirmData);
34122                    
34123                    if (!$result_confirm) {
34124                        $this->log(__METHOD__ . ' Failed to confirm coupon use request. ' . json_encode($requestCouponConfirmData) . ' -- ' . json_encode($data), $logFileName);
34125                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to confirm coupon use request', $data, $requestCouponConfirmData);
34126                        return ;
34127                    }
34128                }
34129                // NJ-47740 end
34130
34131                // NJ-35237
34132                if (!empty($ptPaymentParams['rewardedPoints'])) {
34133                    $rewaredPointParams['ContinuationRewardPoint'] = $ptPaymentParams['rewardedPoints'];
34134                    // save reward point
34135                    if (!$this->ContinuationRewardPoint->saveRewardPoint($rewaredPointParams)) {
34136                        $this->log(__METHOD__ . ' Failed to save reward point. --> ' . json_encode($ptPaymentParams['rewardedPoints']), $logFileName);
34137                        $this->log(__METHOD__ . ' Worldpay: ' . $userId . ' - Failed to save reward point. --> ' . json_encode($ptPaymentParams['rewardedPoints']), 'error');
34138                    }
34139                }
34140                // NJ-35237 end
34141
34142                
34143            }
34144
34145            // set transaction
34146            $dataSource = $this->User->getDataSource();
34147            $dataSource->begin();
34148
34149            if (
34150                $formType != Configure::read('payment_credit_textbook_purchase') &&
34151                $formType != Configure::read('payment_credit_receivable') &&
34152                $formType != Configure::read('payment_credit_appreciation_receivable') &&
34153                $formType != Configure::read('payment_credit_coin_purchase') &&
34154                $formType != Configure::read('payment_native_option_join') &&
34155                $formType != Configure::read('payment_native_option_monthly_payment') &&
34156                $formType != Configure::read('payment_callan_option_join') &&
34157                $formType != Configure::read('payment_callan_option_monthly_payment') &&
34158                $formType != Configure::read('payment_halfway_termination_of_annual_discount_option')
34159            ) {
34160
34161                # user array to be saved
34162                $saveUserArr = array(
34163                    'User' => array(
34164                        'status' => 1,
34165                        'modified' => date('YmdHis'),
34166                        'fail_flg' => 0,
34167                        'charge_flg' => 1,
34168                        'counseling_attended_flg' => 0,
34169                        'card_company' => $card_company,
34170                        'hash16' => $userData['User']['id'],
34171                        'last_charge_date' => date('YmdHis'),
34172                        'payment_plan_id' => $paymentPlanId,
34173                        'price_id' => $priceId,
34174                        'corporate_id' => null,
34175                        'corporate_type' => null,
34176                        'paypal_billing_agreement_id' => null,
34177                        'paypal_payer_id' => null,
34178                        'is_new_premium_flg' => 0,
34179                        'double_check_flg' => 1
34180                    )
34181                );
34182
34183                // if not empty card expiration date
34184                if (isset($ptPaymentParams['cardExpirationDate'])) {
34185                    $saveUserArr['User']['card_expiration_date'] = $ptPaymentParams['cardExpirationDate'];
34186                }
34187
34188                // set child card expiration date same as parent
34189                if (isset($ptPaymentParams['family_data']['applyPlan']['card_expiration_date'])) {
34190                    $saveUserArr['User']['card_expiration_date'] = $ptPaymentParams['family_data']['applyPlan']['card_expiration_date'];
34191                }
34192
34193                // ----
34194                # check payment if credit authentication
34195                if (in_array($formType, array(Configure::read('payment_lite_credit_free'),Configure::read('payment_credit_authentication'), Configure::read('payment_credit_family_free')))) {
34196                    $saveUserArr['User']['first_charge_date'] = date('Y-m-d H:i:s');
34197                    $saveUserArr['User']['platform'] = $platform;
34198                // if complimentary plan unsubscribe and resubscribe
34199                } elseif (isset($ptPaymentParams['updateFirstChargeDate']) || $newYear95percentOffCampaign) {
34200                    $saveUserArr['User']['first_charge_date'] = date('Y-m-d H:i:s');
34201                }
34202
34203                // if bonus coin flg is set
34204                if (isset($ptPaymentParams['bonusCoinFlg'])) {
34205                    $saveUserArr['User']['bonus_coin_flg'] = $ptPaymentParams['bonusCoinFlg'];
34206                }
34207
34208                if (!empty($stripePaymentMethod)) {
34209                    $saveUserArr['User']['stripe_payment_identifier'] = $stripePaymentMethod;
34210                }
34211
34212                if (!empty($stripeCustomerID)) {
34213                    $saveUserArr['User']['stripe_customer_id'] = $stripeCustomerID;
34214                }
34215
34216                //NJ-7874 if appreciation flag and amount is set
34217                if (isset($ptPaymentParams['family_data']['applyPlan']['tip_max_amount']) && $ptPaymentParams['family_data']['applyPlan']['tip_max_amount']) {
34218                    $tipAmount = $ptPaymentParams['family_data']['applyPlan']['tip_max_amount'];
34219                }
34220
34221                if (isset($ptPaymentParams['family_data']['applyPlan']['allow_appreciation_flg']) && $ptPaymentParams['family_data']['applyPlan']['allow_appreciation_flg'] && $tipAmount) {
34222                    $appreciationFlg = 1;
34223                }
34224
34225                // get time today plus 1 hour
34226                $nextChargeTime = (time() + 3600) - strtotime('TODAY');
34227                
34228                # check if subscription payment
34229                if (
34230                    $formType == Configure::read('payment_credit_force_charge') ||
34231                    $formType == Configure::read('payment_credit_retry') ||
34232                    $formType == Configure::read('payment_credit_monthly_payment') ||
34233                    $formType == Configure::read('payment_credit_family_monthly_payment') ||
34234                    $formType == Configure::read('payment_credit_family_free')
34235                ) {
34236
34237                    if ($formType == Configure::read('payment_credit_monthly_payment')) {
34238                        $nextChargeTime = strtotime($userData['next_charge_date']) - strtotime('TODAY');
34239                    }
34240
34241                    // set minutes and seconds to 00:00 always
34242                    $nextChargeDate = date('Y-m-d H:00:00', strtotime('+' . $nextChargeTime . ' second ' . $this->User->getNextChargeDate()));
34243
34244                    # get and set next charge date
34245                    $nextChargeDate = $nextChargeDate = date('Y-m-d H:00:00', strtotime('+' . (time() - strtotime('TODAY')) . ' second ' . $this->User->getNextChargeDate()));
34246                    $saveUserArr['User']['next_charge_date'] = $nextChargeDate;
34247                    $saveUserArr['User']['double_check_flg'] = 1;
34248                    $saveUserArr['User']['expired_card_flg'] = 0; // NC-3902
34249
34250                    // NJ-1562 - appreciation on
34251                    if( $paymentPlanId && in_array( $paymentPlanId, Configure::read('appreciation.payment_plan_id') ) ) {
34252                        //$saveUserArr['User']['allow_appreciation_flg'] = 1; // on
34253                        if (in_array($paymentPlanId,Configure::read('appreciation.can_coin_purchase_check')) ) {
34254                            //set the appreciation flg to be set
34255                            $saveUserArr['User']['allow_appreciation_flg'] = $appreciationFlg;
34256                            $saveUserArr['User']['show_appreciation_flg'] = $appreciationFlg;
34257                            $saveUserArr['User']['tip_max_amount'] = $tipAmount;
34258                        }else{
34259                            $saveUserArr['User']['allow_appreciation_flg'] = 1; // on
34260
34261                            if (
34262                                $formType == Configure::read('payment_credit_force_charge') || 
34263                                $formType == Configure::read('payment_credit_retry') || 
34264                                $formType == Configure::read('payment_lite_credit_paid')
34265                            ) {
34266                                $showAppreciationFlg = 0;//set  the default show appreciation flg
34267
34268                                //NJ-7548 : check user birthday and age ; $userData['User']['birthday']
34269                                $userAge = UserTable::getStudentAge($userData['User']['birthday']);
34270                                $userAge = $userAge ? (int) $userAge : null;
34271
34272                                //change the show appreciation flg if no birthday set or 18 and above
34273                                if (!$userAge || $userAge >= 18) {
34274                                    $showAppreciationFlg = 1;
34275                                }
34276
34277                                $saveUserArr['User']['show_appreciation_flg'] = $showAppreciationFlg; // on
34278                            }
34279                        }
34280                    }
34281                    
34282                    if ($formType == Configure::read('payment_credit_family_free')) {
34283                        $nextChargeDate = date('Y-m-d H:00:00', strtotime('+' . $nextChargeTime . ' second ' . $this->User->getFirstNextChargeDate()));
34284                        $saveUserArr['User']['next_charge_date'] = $nextChargeDate;
34285                    }
34286
34287                    # give points to user join the campaign who retry payment
34288                    if ($formType == Configure::read('payment_credit_retry') && !$isLitePlanUser) {
34289                        $this->ContinuationCampaign->givePointsRetrySuccess(array(
34290                            'user_ids' => array($userData['User']['id'])
34291                        ));
34292                    }
34293
34294                    # give points if user join campaign and success payment
34295                    if ($formType == Configure::read('payment_credit_monthly_payment')) {
34296                        $this->ContinuationCampaign->givePoints(array(
34297                            'user_id' => $userData['User']['id']
34298                        )); 
34299                    }
34300
34301                    # give coins if temporary/new user is changed/added to family plan
34302                    if ($formType == Configure::read('payment_credit_family_free') && $userData['User']['status'] == 0) {
34303                        // NJ-4746: defult bonus point
34304                        $defaultBC = ClassRegistry::init("DefaultCoinRegistration")->defaultCoins();
34305                        $bonusPoints = (($defaultBC > 0) ? $defaultBC : Configure::read("credit.bonus_coin_authentication"));
34306
34307                        // camapaign master triiger 1
34308                        $campaignMaster = ClassRegistry::init('CampaignMaster')->bonusTrigger(['userId' => $userData['User']['id'], 'triggerNo' => 1]);
34309                        if (!$campaignMaster['bonusCoins'] && !$campaignMaster['bonusCoupons']) {
34310                            # add to the user's existing coin
34311                            $pointParams = array(
34312                                'userId' => $userData['User']['id'],
34313                                'point' => $bonusPoints,
34314                                'kbn' => Configure::read("point_history.bonus"),
34315                                'kbnType' => 1, // add coin
34316                                'coinType' => 2, // service coin
34317                                'coinFailMessage' => Configure::read('coin.failed.campaign')
34318                            );
34319                            if (!$this->UsersPoint->performPointTransaction($pointParams)) {
34320                                $this->log(__METHOD__ . ' Failed add point to user. ' . json_encode($pointParams) . ' -- ' . json_encode($data), $logFileName);
34321                                $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed add point to user', $data, $pointParams);
34322                                $dataSource->rollback();
34323                                $dataSource->commit();
34324                                return ;
34325                            }
34326                        }
34327                    }
34328
34329                    # give points if user join retry payment lite 
34330                    if ($formType == Configure::read('payment_credit_retry') && $isLitePlanUser) {
34331                        $this->liteUserAddCoinRewardForReenroll(array('id' => $userData['User']['id']));
34332                    }
34333
34334                } elseif (
34335                    $formType ==  Configure::read('payment_credit_authentication') || 
34336                    $formType == Configure::read('payment_lite_credit_free')
34337                ) {
34338                    // set minutes and seconds to 00:00 always
34339                    $nextChargeDate = date('Y-m-d H:00:00', strtotime('+' . $nextChargeTime . ' second ' . $this->User->getFirstNextChargeDate()));
34340                    $saveUserArr['User']['next_charge_date'] = $nextChargeDate;
34341
34342                    // NJ-1562 - appreciation on
34343                    if( $paymentPlanId && in_array( $paymentPlanId, Configure::read('appreciation.payment_plan_id') ) ) {
34344                        //$saveUserArr['User']['allow_appreciation_flg'] = 1; // on
34345                        if (in_array($paymentPlanId,Configure::read('appreciation.can_coin_purchase_check')) ) {
34346                            //set the appreciation flg to be set
34347                            $saveUserArr['User']['allow_appreciation_flg'] = $appreciationFlg;
34348                            $saveUserArr['User']['show_appreciation_flg'] = $appreciationFlg;
34349                            $saveUserArr['User']['tip_max_amount'] = $tipAmount;
34350                        }else{
34351                            $saveUserArr['User']['allow_appreciation_flg'] = 1; // on
34352
34353                            $showAppreciationFlg = 0;
34354
34355                            //NJ:7548: fetch the age of the user
34356                            $uAge = UserTable::getStudentAge($userData['User']['birthday']);
34357                            $uAge = $uAge ? (int) $uAge : null;
34358
34359                            //change the show appreciation flg if no birthday set or 18 and above
34360                            if (!$uAge || $uAge >= 18) {
34361                                $showAppreciationFlg = 1;
34362                            }
34363
34364                            //set the save user array 
34365                            $saveUserArr['User']['show_appreciation_flg'] = $showAppreciationFlg; // set
34366                        }
34367                    }
34368                }
34369
34370                #NJ-7548 : if credit card changed to zeus 
34371                if (
34372                    $formType == Configure::read('payment_credit_change') && 
34373                    $paymentPlanId && in_array( $paymentPlanId, Configure::read('appreciation.payment_plan_id') )
34374                ) {
34375                    
34376                    if (in_array($paymentPlanId,Configure::read('appreciation.can_coin_purchase_check')) ) {
34377                        //set the appreciation flg to be set
34378                        $saveUserArr['User']['allow_appreciation_flg'] = $appreciationFlg;
34379                        $saveUserArr['User']['show_appreciation_flg'] = $appreciationFlg;
34380                        $saveUserArr['User']['tip_max_amount'] = $tipAmount;
34381                    }else{
34382                        $saveUserArr['User']['allow_appreciation_flg'] = 1; // on
34383
34384                        $showAppreciationFlg = 0;//set  the default show appreciation flg
34385
34386                        //NJ-7548 : check user birthday and age ; $userData['User']['birthday']
34387                        $userAge = UserTable::getStudentAge($userData['User']['birthday']);
34388                        $userAge = $userAge ? (int) $userAge : null;
34389
34390                        //change the show appreciation flg if no birthday set or 18 and above
34391                        if (!$userAge || $userAge >= 18) {
34392                            $showAppreciationFlg = 1;
34393                        }
34394
34395                        $saveUserArr['User']['show_appreciation_flg'] = $showAppreciationFlg; // on
34396                    }
34397                }
34398
34399
34400                // if credit card change from android or apple
34401                if (
34402                    in_array($formType, array(Configure::read('payment_credit_change'), Configure::read('payment_credit_authentication'))) &&
34403                    in_array($userData['User']['card_company'], array(Configure::read('card_company.apple'), Configure::read('card_company.google')))
34404                ) {
34405                    // NC-5007 add to user's existing number of coins
34406                    $pointParams = array(
34407                        'userId' => $userData['User']['id'],
34408                        'point' => 500,
34409                        'kbn' => 6,
34410                        'kbnType' => 1, // add coin
34411                        'coinType' => 2, // service coin
34412                        'coinFailMessage' => Configure::read('coin.failed.campaign')
34413                    );
34414                    if (!$this->UsersPoint->performPointTransaction($pointParams)) {
34415                        $this->log(__METHOD__ . ' Failed add point to user. ' . json_encode($pointParams) . ' -- ' . json_encode($data), $logFileName);
34416                        $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed add point to user', $data, $pointParams);
34417                        $dataSource->rollback();
34418                        $dataSource->commit();
34419                        return ;
34420                    }
34421
34422                    // log for debugging
34423                    $this->log("[STRIPEPAY] switching user from android/ios to zeus -> " . json_encode($data), $logFileName);
34424                }
34425
34426                $discountOption = isset($ptPaymentParams['discountOption']) ? $ptPaymentParams['discountOption'] : [];
34427                $zeroStudentDiscount = false;
34428
34429                # update the user information
34430                $this->User->validate = array();
34431                if (!$read = $this->User->read(null, $userData['User']['id'])) {
34432                    $this->log(__METHOD__ . ' User id does not exist. ' . json_encode($userData) . ' -- ' . json_encode($data), $logFileName);
34433                    $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'User id does not exist', $data, $userData);
34434                    $dataSource->rollback();
34435                    $dataSource->commit();
34436                    return ;
34437                }
34438                $currency_before = $userData['User']['currency_code'];
34439                $plan_before = $userData['User']['payment_plan_id'];
34440
34441                $famRegist = false;
34442                // NC-4673: update family parent_id, memo and monthly_payment
34443
34444
34445                if (
34446                    in_array($formType, Configure::read('family_plan_form_types'))
34447                ) {
34448                    // if parent_id is empty
34449                    if (empty($read['User']['parent_id'])) {
34450                        $saveUserArr['User']['parent_id'] = $data['sendid'];
34451                        $saveUserArr['User']['memo'] = date('Y/m/d H:i:s')." Family plan[User]: family registration \n".$read['User']['memo'];
34452                        $famRegist = true;
34453
34454                
34455                        if (empty($read['User']['currency_code'])) {
34456                            $saveUserArr['User']['currency_code'] = $currencyCode;
34457                        }
34458                    }
34459                }
34460
34461                $this->User->set($saveUserArr);
34462                if (!$this->User->save()) {
34463                    $this->log(__METHOD__ . ' Failed update user data. ' . json_encode($saveUserArr) . ' -- ' . json_encode($data), $logFileName);
34464                    $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed update user data', $data, $saveUserArr);
34465                    $dataSource->rollback();
34466                    $dataSource->commit();
34467                    return ;
34468                }
34469
34470                // check if payment plan upgrade
34471                if ($formType == Configure::read('payment_lite_plan_upgrade')) {
34472                    // get user zero student discount term
34473                    $discountOptionTermData = $this->UserDiscountOptionsTerm->getTerm([
34474                        'user_id' =>  $userId,
34475                        'discount_option_id' => Configure::read('discount_option.zero_student.plan_id'),
34476                        'status' => 1
34477                    ]);
34478
34479                    // stop zero student discount
34480                    if ($discountOptionTermData) {
34481                        // open tunnel
34482                        myTools::initializeApiTunnel(['DiscountOptionController']);
34483
34484                        // initialize controller
34485                        $doc = new DiscountOptionController();
34486
34487                        $docParams = [
34488                            'discountOptionId' => $discountOptionTermData['discount_option_id'],
34489                            'discountOptionPriceId' => $discountOptionTermData['discount_option_price_id'],
34490                            'termId' => $discountOptionTermData['discount_option_term_id'],
34491                            'cancellationFee' => 0,
34492                            'cancellationType' => Configure::read('discount_option.dosh_type.plan_change'),
34493                            'userData' => $userData['User'],
34494                            'fromController' => $this->request->params['controller'],
34495                            'fromAction' => $this->request->params['action'],
34496                            'doshStatus' => Configure::read('discount_option.dosh_status.midterm_cancellation')
34497                        ];
34498
34499                        // set data
34500                        $doc->params = $docParams;
34501
34502                        if (!$doc->stopDiscountOption()) {
34503                            $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to stop discount option. ', $docParams);
34504                            $dataSource->rollback();
34505                            $dataSource->commit();
34506                            return ;
34507                        }
34508                    }
34509                }
34510
34511                // if user plan has discount option
34512                if ($discountOption) {
34513                    $contractStart = $formType != Configure::read('payment_credit_authentication') ? date('Y-m-d 00:00:00') : (isset($nextChargeDate) ? $nextChargeDate : $this->User->getFirstNextChargeDate());
34514                    if (
34515                        (
34516                            $discountOption['discount_option_id'] == Configure::read('discount_option.zero_student.plan_id') &&
34517                            $formType == Configure::read('payment_lite_credit_monthly_payment') && 
34518                            isset($ptPaymentParams['userRegister']) &&
34519                            $ptPaymentParams['userRegister']
34520                        ) ||
34521                        in_array(
34522                            $formType,
34523                            [
34524                                Configure::read('payment_credit_authentication'),
34525                                Configure::read('payment_credit_force_charge'),
34526                                Configure::read('payment_lite_plan_upgrade')
34527                            ]
34528                        )
34529                    ) {
34530                        // set amount to 0 if card auth
34531                        if ($formType == Configure::read('payment_credit_authentication')) {
34532                            $discountOption['amount'] = 0;
34533                        }
34534
34535                        // set data for user discount option term
34536                        $udotData = [
34537                            'userId' => $userId,
34538                            'discountOptionId' => $discountOption['discount_option_id'],
34539                            'discountOptionPriceId' => $discountOption['discount_option_price_id'],
34540                            'contractStart' => $contractStart,
34541                            'logFileName' => $logFileName,
34542                            'paymentId' => $paymentSaveID,
34543                            'discountAmount' => $discountOption['amount'],
34544                            'doshEvent' => isset($discountOption['dosh_event']) ? $discountOption['dosh_event'] : null,
34545                            'currencyCode' => $currencyCode,
34546                            'doshStatus' => isset($discountOption['dosh_status']) ? $discountOption['dosh_status'] : null,
34547                            'formType' => $formType,
34548                            'userRegister' => isset($ptPaymentParams['userRegister']) ? true : false
34549                        ];
34550
34551                        if (isset($discountOption['dosh_type'])) {
34552                            $udotData['doshType'] = $discountOption['dosh_type'];
34553                        }
34554
34555                        if (
34556                            $discountOption['discount_option_id'] == Configure::read('discount_option.zero_student.plan_id') &&
34557                            $formType == Configure::read('payment_lite_credit_monthly_payment')
34558                        ) {
34559                            $zeroStudentDiscount = true;
34560                        }
34561
34562                        // create user discount option term
34563                        if (!$this->UserDiscountOptionsTerm->createTerm($udotData)) {
34564                            $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to create user discount option term. ', $udotData);
34565                            $dataSource->rollback();
34566                            $dataSource->commit();
34567                            return ;
34568                        }
34569
34570                        // check if has uploaded data for zero student document(s)
34571                        if (isset($discountOption['application_form_app_image_url'])) {
34572                            $applicationData = [
34573                                'user_id' => $userId,
34574                                'image_url' => $discountOption['application_form_app_image_url']
34575                            ];
34576            
34577                            // save document url
34578                            if (!$this->StudentDiscountApplicationForm->saveApplicationForm($applicationData)) {
34579                                $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save zero student application form. ', $applicationData);
34580                                $dataSource->rollback();
34581                                $dataSource->commit();
34582                                return ;
34583                            }
34584
34585                            $udData = [
34586                                'user_id' => $userId,
34587                                'individual_card_fail_flg'    => 0,
34588                                'show_zero_student_discount_option_flg' => 1
34589                            ];
34590
34591                            $this->UsersDetail->clear();
34592                            $this->UsersDetail->set($udData);
34593                            $this->UsersDetail->validate = [];
34594                            if (!$this->UsersDetail->save()) {
34595                                $this->log(__METHOD__ . ' Failed insert users detail data. ' . json_encode($udData) . ' -- ' . json_encode($data), $logFileName);
34596                                $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to insert users detail data. ', $udData);
34597                                $dataSource->rollback();
34598                                $dataSource->commit();
34599                                return ;
34600                            }
34601
34602                            $slackParams = [
34603                                'userId' => $userId,
34604                                'nickname' => $userData['User']['nickname'],
34605                                'nextChargeDate' => $this->User->getNextChargeDate(),
34606                                'applicationCnt' => 1,
34607                                'appFormUrl' => $discountOption['application_form_app_image_url']
34608                            ];
34609
34610                            // send slack
34611                            StudentDiscountApplicationFormTable::sendSlackStudentDiscountInfo($slackParams);
34612                        }
34613                    } elseif (in_array($formType, [Configure::read('payment_credit_monthly_payment'), Configure::read('payment_credit_retry')])) {
34614                        $discountOption += [
34615                            'contract_start' => $contractStart,
34616                            'currency_code' => $currencyCode,
34617                            'payment_id' => $paymentSaveID,
34618                            'dosh_settlement_status' => 1, // success
34619                            'form_type' => $formType
34620                        ];
34621
34622                        if (!$this->UserDiscountOptionsTerm->processMonthlyDiscountOption($discountOption)) {
34623                            $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to process monthly discount option. ', $discountOption);
34624                            $dataSource->rollback();
34625                            $dataSource->commit();
34626                            return ;
34627                        }
34628                    }
34629
34630                    if (
34631                        (
34632                            in_array(
34633                                $formType,
34634                                [
34635                                    Configure::read('payment_credit_authentication'),
34636                                    Configure::read('payment_credit_force_charge'),
34637                                    Configure::read('payment_lite_plan_upgrade')
34638                                ]
34639                            ) ||
34640                            (
34641                                $discountOption['discount_option_id'] == Configure::read('discount_option.zero_student.plan_id') &&
34642                                $formType == Configure::read('payment_lite_credit_monthly_payment') && 
34643                                isset($ptPaymentParams['userRegister']) &&
34644                                $ptPaymentParams['userRegister']
34645                            )
34646                        ) &&
34647                        isset($discountOption['option_after_name']) &&
34648                        isset($discountOption['option_type'])
34649                    ) {
34650                        $adoLogParams = [
34651                            'user_id' => $userId,
34652                            'platform' => $platform,
34653                            'status' => 1, // subscribe
34654                            'controller_name' => $this->request->params['controller'],
34655                            'action_name' => $this->request->params['action'],
34656                            'user_type' => 0, // normal user
34657                            'option_before' => '',
34658                            'option_after' => 1,
34659                            'option_before_name' => isset($discountOption['option_before_name']) ? $discountOption['option_before_name'] : '',
34660                            'option_after_name' => $discountOption['option_after_name'],
34661                            'option_type' => $discountOption['option_type'],
34662                            'payment_plan_id' => $paymentPlanId
34663                        ];
34664
34665                        if (!$this->UserOptionChangeLog->saveOptionChangeLog($adoLogParams)) {
34666                            $this->log(__METHOD__ . ' Failed to update option change. ' . json_encode($adoLogParams), $logFileName);
34667                            $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'Failed to update user data', $adoLogParams);
34668                            $dataSource->rollback();
34669                            $dataSource->commit();
34670                            return ;
34671                        }
34672                    }
34673                }
34674
34675                # NJ-18780 : changed plan to liteplan
34676                if (
34677                    $formType == Configure::read('payment_lite_plan_downgrade') || 
34678                    $formType == Configure::read('payment_lite_plan_upgrade')
34679                ) {
34680                    $this->User->openDBReplica();
34681                    $_currentUser = $this->User->find('first', array(
34682                        'fields' => array('User.parent_id', 'User.currency_code', 'User.payment_plan_id','User.memo','User.native_option','User.callan_option','next_charge_date'),
34683                        'conditions' => array('User.id' => $userData['User']['id']),
34684                        'recursive' => -1
34685                    ));
34686                        $this->User->closeDBReplica();
34687
34688                    $_memoCoins = 'SC and PC';
34689                    $_updateMemo = '';
34690                    $litenativeOptionBefore = $litenativeOptionAfter = $_currentUser['User']['native_option'];
34691                       $litecallanOptionBefore = $litecallanOptionAfter = $_currentUser['User']['callan_option'];
34692                       $isliteNativeOptionChange = $isliteCallanOptionChange = false;
34693
34694                       $liteUserUpdateArr = array();
34695                       $_dateNow = date("Y-m-d H:i:s");
34696
34697                    // - turn off native option if it is on
34698                    if ((int) $litenativeOptionBefore == 1) {
34699                        $liteUserUpdateArr['native_option'] = 0; // turn off
34700                        $liteUserUpdateArr['native_option_cancellation_time'] = $dateNow;
34701                        $litenativeOptionAfter = 0;
34702                        $isliteNativeOptionChange = true;
34703
34704                        // set memo
34705                        $_updateMemo = $_updateMemo. "\n{$_dateNow} \nChanged by due Selected Light Plan / Native Unlimited option OFF";
34706                    }
34707
34708                    // - turn off callan option if it is on
34709                    if ((int) $litecallanOptionBefore == 1) {
34710                        $liteUserUpdateArr['callan_option'] = 0; // turn off
34711                        $liteUserUpdateArr['callan_option_cancellation_time'] = $dateNow;
34712                        $litecallanOptionAfter = 0;
34713                        $isliteCallanOptionChange = true;
34714
34715                        $_updateMemo = $_updateMemo. "\n{$_dateNow} \nChanged by due Selected Light Plan / Callan Unlimited option OFF";
34716                    }
34717
34718                    // - changing to lite plan
34719                    if ($formType == Configure::read('payment_lite_plan_downgrade')) {
34720                    
34721                        // - confiscate all mc coins
34722                        $_monthlyPoints = $this->UsersPoint->getCurrentUserMCPoint($userData['User']['id']); 
34723                        $_memoCoins = "MC";
34724
34725                        if ((int) $_monthlyPoints > 0) {
34726                            $confiscateParams = array(
34727                                'userId' => $userData['User']['id'],
34728                                'point' => $_monthlyPoints,
34729                                'kbn' => 18, 
34730                                'coinType' => 3
34731                            );
34732
34733
34734                            // rollback if confiscating points failed
34735                            if (!$confiscateCoinFlg = $this->UsersPoint->confiscateUserLitePoints($confiscateParams)) {
34736                                $this->log(__METHOD__ . ' Failed to confiscate points. --> ' . json_encode($confiscateParams) . ' -- ' . json_encode($data), $logFileName);
34737                                        
34738                                $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userData['User']['id'], 'Failed to confiscate points.', $userData);
34739                                $dataSource->rollback();
34740                                $dataSource->commit();
34741                                return ;
34742                            }
34743
34744                            $_updateMemo = $_updateMemo . "\n {$_dateNow} (Previous Coins ({$_memoCoins})【Confiscated】 : {$_monthlyPoints}. )";
34745                        }
34746
34747                        $doneConfiscatePoints = ClassRegistry::init('UsersPointHistory')->confiscateUserLitePointsCoinBox($userData['User']['id']);
34748
34749                        $nextChargeDateLite = $this->User->getNextChargeDate();
34750
34751                        // - give lite bonus coins
34752                        $_pointParams = array(
34753                            'userId' => $userData['User']['id'],
34754                            'point' => Configure::read('lite_plan_monthly_coin'),
34755                            'kbn' => Configure::read('lite_plan_bonus_kbn'), // 
34756                            'kbnType' => 1, // add coin
34757                            'coinType' => 3, // mc coin
34758                            'dateExpiration' => $nextChargeDateLite,
34759                            'coinFailMessage' => Configure::read('coin.failed.membership')
34760                        );
34761
34762                        // rollback if adding  points failed
34763                        if (!$_addCoinsFlg = $this->UsersPoint->performPointTransaction($_pointParams)) {
34764                            $this->log(__METHOD__ . ' Failed to give points. --> ' . json_encode($confiscateParams) . ' -- ' . json_encode($data), $logFileName);
34765                                    
34766                            $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to give points.', $data);
34767                            $dataSource->rollback();
34768                            $dataSource->commit();
34769                            return ;
34770                        }
34771
34772                        $_coins = Configure::read('lite_plan_monthly_coin');
34773                        $updateMemo = $updateMemo . "\n {$_dateNow} | Light Plan Bonus Coins (MC): {$_coins}";
34774                    }
34775
34776                    // - changing from premium to lite plan
34777                    if ($formType == Configure::read('payment_lite_plan_upgrade')) {
34778                        // - confiscate all held coins
34779                        $_monthlyPoints = $this->UsersPoint->getCurrentUserMCPoint($userData['User']['id']); //  mc coins
34780
34781                        $_memoCoins = "MC";
34782
34783                        if ((int) $_monthlyPoints > 0) {
34784                            $confiscateParams = array(
34785                                'userId' => $userData['User']['id'],
34786                                'point' => $_monthlyPoints,
34787                                'kbn' => 18, 
34788                                'coinType' => 3
34789                            );
34790
34791
34792                            // rollback if confiscating points failed
34793                            if (!$confiscateCoinFlg = $this->UsersPoint->confiscateUserLitePoints($confiscateParams)) {
34794                                $this->log(__METHOD__ . ' Failed to confiscate points. --> ' . json_encode($confiscateParams) . ' -- ' . json_encode($data), $logFileName);
34795                                        
34796                                $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userData['User']['id'], 'Failed to confiscate points.', $userData);
34797                                $dataSource->rollback();
34798                                $dataSource->commit();
34799                                return ;
34800                            }
34801
34802                            $_updateMemo = $_updateMemo . "\n {$_dateNow} (Previous Coins ({$_memoCoins})【Confiscated】 : {$_monthlyPoints}. )";
34803                        }
34804
34805                        $_doneConfiscatePoints = ClassRegistry::init('UsersPointHistory')->confiscateUserLitePointsCoinBox($userData['User']['id']);
34806                    }
34807
34808                    #update the user information memo
34809                    if (empty($_updateMemo)) {
34810
34811                        $_updateMemo = $_updateMemo . "\n" . $_currentUser['User']['memo'];
34812                     
34813                        $_userUpdate = array(
34814                            'id' => $userData['User']['id'],
34815                            'memo' => $_updateMemo
34816                        );
34817
34818                        $this->User->set($_userUpdate);
34819                        if (!$this->User->save()) {
34820                            $this->log(__METHOD__ . ' Failed to update user data. ' . json_encode($_userUpdate), $logFileName);
34821                            $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed to update user data', $_userUpdate);
34822                            $dataSource->rollback();
34823                            $dataSource->commit();
34824                            return ;
34825                        }
34826                    }
34827
34828                    // - update the user information
34829                    if ($liteUserUpdateArr) {
34830                        $liteUserUpdateArr['id'] = $userData['User']['id'];
34831
34832                        // - set user 
34833                        $this->User->set($liteUserUpdateArr);
34834
34835                        if (!$this->User->save()) {
34836                            $this->log(__METHOD__ . ' Failed to update user data. ' . json_encode($liteUserUpdateArr), $logFileName);
34837                            $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed to update user data', $_userUpdate);
34838                            $dataSource->rollback();
34839                            $dataSource->commit();
34840                            return ;
34841                        }
34842                    }
34843
34844                    # add log if there is change on native option
34845                    if ($isliteNativeOptionChange) {
34846                        $optionLogParams = array(
34847                            'user_id' => $userData['User']['id'],
34848                            'platform' => Configure::read('platform.pclp'),
34849                            'status' => 3,//set to unsubscribe
34850                            'controller_name' => $this->request->params['controller'],
34851                            'action_name' => $this->request->params['action'],
34852                            'user_type' => 0, // user
34853                            'option_before' => 1,
34854                            'option_after' => '',
34855                            'option_before_name' => 'Native Unlimited Option',
34856                            'option_after_name' => '',
34857                            'option_type' => 1,
34858                            'payment_plan_id' => $paymentPlanId
34859                        );
34860
34861                        $_saveLog = ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
34862
34863                        if (!$_saveLog) {
34864                            $this->log(__METHOD__ . ' Failed to update option change. ' . json_encode($optionLogParams), $logFileName);
34865                            $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed to update user data', $optionLogParams);
34866                            $dataSource->rollback();
34867                            $dataSource->commit();
34868                            return ;
34869                        }
34870                    }
34871
34872                    # add log if change on callan option 
34873                    if ($isliteCallanOptionChange) {
34874
34875                        $optionLogParams = array(
34876                            'user_id' => $userId,
34877                            'platform' => Configure::read('platform.pclp'),
34878                            'status' => 3,//unsubscribe
34879                            'controller_name' => $this->request->params['controller'],
34880                            'action_name' => $this->request->params['action'],
34881                            'user_type' => 0, // user
34882                            'option_before' => 1,
34883                            'option_after' => '',
34884                            'option_before_name' => 'Callan Unlimited Option',
34885                            'option_after_name' => '',
34886                            'option_type' => 2,
34887                            'payment_plan_id' => $paymentPlanId
34888                        );
34889
34890                        $_saveLog = ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
34891
34892                        // rollback if confiscating points failed
34893                        if (!$_saveLog) {
34894                            $this->log(__METHOD__ . ' Failed to save user option change log. --> ' . json_encode($optionLogParams) . ' -- ' . json_encode($data), $logFileName);
34895                                    
34896                            $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save option log.', $optionLogParams);
34897                            $dataSource->rollback();
34898                            $dataSource->commit();
34899                            return ;
34900                        }
34901                    }
34902                }
34903                
34904
34905                // NC-7459 check previus user status, add coinbox challenge
34906                if (
34907                    isset($read['User']['payment_plan_id'])
34908                    && $read['User']['payment_plan_id'] == Configure::read('payment_plans.complimentary_plan')
34909                    && isset($read['User']['complimentary_code'])
34910                ) {
34911
34912                    // get complimentary coin award
34913                    $coinAward = $this->ComplimentaryCode->find('first', array(
34914                        'fields' => array('coin_award'),
34915                        'conditions' => array(
34916                            'ComplimentaryCode.code' => $read['User']['complimentary_code'],
34917                            'ComplimentaryCode.template_type !=' => 0 // // Free trial
34918                        )
34919                    ));
34920
34921                    if (
34922                        isset($coinAward['ComplimentaryCode']['coin_award'])
34923                        && $coinAward['ComplimentaryCode']['coin_award']
34924                    ) { // @TODO use common @note did not use CoinBox->addCoinReward because it will not succeed for unknown reason.
34925                        $coinboxSet = array(
34926                            'status' => 1,
34927                            'user_id' => $userData['User']['id'],
34928                            'teacher_id' => null,
34929                            'coin_event_id' => Configure::read('coin_box_event.complimentary'),
34930                            'coin' => $coinAward['ComplimentaryCode']['coin_award'],
34931                            'lesson_id' => NULL,
34932                            'expiration_date' => date('Y-m-d 23:59:59', strtotime('+59 days'))
34933                        );
34934                        $this->CoinBox->create();
34935                        $this->CoinBox->set($coinboxSet);
34936                        if (!$this->CoinBox->save()) {
34937                            CakeLog::debug('[debug_payment_proceed] complimentary coin award : ' . json_encode($saveUserArr));
34938                            $this->log(__METHOD__ . ' Failed adding complimentary coin award . ' . json_encode($saveUserArr) . ' -- ' . json_encode($data) . ' -- ' . json_encode($coinAward), $logFileName);
34939                            $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed adding complimentary coin award', $data, $coinboxSet);
34940                            $dataSource->rollback();
34941                            $dataSource->commit();
34942                            return ;
34943                        }
34944                    }
34945                }
34946                
34947                $memKey = 'family_reactivation_' . $data['sendid'] . '_' . $familyId;
34948                $familyReactivation = $this->memcache->get($memKey);
34949                // NC-3754 : add memo for reactivation parent user.
34950                if ($formType == Configure::read('payment_credit_family_monthly_payment') && !empty($read['User']['parent_id']) && $familyReactivation) {
34951                    $famRegist = false;
34952                    // delete memcache
34953                    $this->memcache->delete($memKey);
34954                    $this->User->clear();
34955                    if (!$userRead = $this->User->read(array('memo'), $data['sendid'])) {
34956                        $this->log(__METHOD__ . ' User id does not exist. ' . json_encode($data), $logFileName);
34957                        $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'User id does not exist', $data);
34958                        $dataSource->rollback();
34959                        $dataSource->commit();
34960                        return ;
34961                    }
34962
34963                    $this->User->set(array('memo' => date('Y/m/d H:i:s')." Family plan[User]: family id: " . $userData['User']['id'] . " reactivation \n" . $userRead['User']['memo']));
34964                    $this->User->validate = false;
34965                    if (!$this->User->save()) {
34966                        $this->log(__METHOD__ . ' Failed update user data. ' . json_encode($userRead) . ' -- ' . json_encode($data), $logFileName);
34967                        $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed update user data', $data, $userRead);
34968                        $dataSource->rollback();
34969                        $dataSource->commit();
34970                        return ;
34971                    }
34972                }
34973
34974                // NC-3754 
34975                // Proccess Family Plan
34976                if($famRegist && !$familyReactivation) {
34977                    // @param:  parent id. for memcache key.
34978                    $famPlanRes = $this->FamilyPlanList->processFamPlan($data['sendid'], $familyId, $data['sendpoint']);
34979                    if ($famPlanRes != "[OK]") {
34980                        $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], $famPlanRes, $data);
34981                        $dataSource->rollback();
34982                        $dataSource->commit();
34983                        return;
34984                    }
34985                }
34986
34987                // check if membership status was change
34988                if (isset($ptPaymentParams['statusBefore']) && isset($ptPaymentParams['statusAfter']) && isset($ptPaymentParams['platform'])) {
34989                    $currentUser = $this->User->find('first', array(
34990                        'fields' => array('User.parent_id', 'User.currency_code', 'User.payment_plan_id'),
34991                        'conditions' => array('User.id' => $userId),
34992                        'recursive' => -1
34993                    ));
34994                    $parentId = $currentUser['User']['parent_id'];
34995                    $is_cron = 0;
34996                    if (php_sapi_name() == 'cli' || $ptPaymentParams['logFileName'] == 'retry_monthly_payment'){
34997                        $is_cron = 1;
34998                    } 
34999                       $currency_after = $currentUser['User']['currency_code'];
35000                       $plan_after = $currentUser['User']['payment_plan_id'];
35001
35002                    $usclData = array(
35003                        'user_id' => $userId,
35004                        'platform' => $ptPaymentParams['platform'] ?? '',
35005                        'card_company_before' => $read['User']['card_company'],
35006                        'status_before' => $ptPaymentParams['statusBefore'],
35007                        'status_after' => $ptPaymentParams['statusAfter'],
35008                        'controller_name' => $this->request->params['controller'],
35009                        'action_name' => $this->request->params['action'],
35010                        'parent_id' => $parentId,
35011                        'is_cron' => $is_cron,
35012                        'currency_before' => $currency_before,
35013                        'currency_after' => $currency_after,
35014                        'payment_plan_id_before' => $plan_before,
35015                        'payment_plan_id_after' => $plan_after,
35016                        'default_appreciation_flg' => $appreciationFlg,
35017                        'default_appreciation_amount' => $tipAmount
35018                    );
35019                    // save user change membership status
35020                    if (!$this->UserStatusChangeLog->saveLog($usclData)) {
35021                        $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'Unable to update status change log', $usclData);
35022                        $dataSource->rollback();
35023                        $dataSource->commit();
35024                        return;
35025                    }
35026                }
35027
35028                # check if user is temporary
35029                if (
35030                    ($userData['User']['status'] == 0 && $formType == Configure::read('payment_credit_authentication')) || 
35031                    ($userData['User']['status'] == 0 && $formType == Configure::read('payment_lite_credit_free') )
35032                ) {
35033                    # update user's status after step 4
35034                    $this->User->validate = array();
35035                    if (!$this->User->read(null, $userData['User']['id'])) {
35036                        $this->log(__METHOD__ . ' User id does not exist. ' . json_encode($userData), $logFileName);
35037                        $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'User id does not exist', $userData);
35038                        $dataSource->rollback();
35039                        $dataSource->commit();
35040                        return ;
35041                    }
35042                    $this->User->set('status', 1);
35043                    if (!$this->User->save()) {
35044                        $this->log(__METHOD__ . ' Failed update user status to 1. ' . json_encode($data), $logFileName);
35045                        $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed update user status to 1', $data);
35046                        $dataSource->rollback();
35047                        $dataSource->commit();
35048                        return ;
35049                    }
35050                }
35051
35052                // NC-7779 : check if user has chivox monthly test taken for the current month, and monthly_speaking_attended_flg ON,
35053                // turn Off the flag if users has not yet taken the exam for the current month.
35054                // @TODO check query
35055                if (
35056                    isset($userData['User']['monthly_speaking_attended_flg']) && isset($userData['User']['monthly_speaking_business_attended_flg'])
35057                    && ($userData['User']['monthly_speaking_attended_flg'] == 1 || $userData['User']['monthly_speaking_business_attended_flg'] == 1)
35058                ) {
35059
35060                    // check chivox monthly
35061                    $paymentPlanIdsForChivoxMonthly = Configure::read('chivox.monthly.user_payment_plan_cantake_exam');
35062                    if (in_array($paymentPlanId, $paymentPlanIdsForChivoxMonthly)) {
35063
35064                        // load model
35065                        $this->loadModel("UsersChivoxMonthlyTest");
35066                        $userTestMonthFlagParams['user_id'] = $userData['User']['id'];
35067                        $userTestMonthFlag = $this->UsersChivoxMonthlyTest->checkUserCurrentMonthExam($userTestMonthFlagParams);
35068
35069                        $monthly_speaking_attended_flg = Configure::read('chivox.test_data_test_type.daily'); // test_type daily speaking 0
35070                        $monthly_speaking_business_attended_flg = Configure::read('chivox.test_data_test_type.business'); // test_type business 1
35071                        $fieldsToUpdate = array();
35072
35073                        // if user hat not yet taken the exam for current month
35074                        if (!in_array($monthly_speaking_attended_flg, $userTestMonthFlag)) {
35075                            $fieldsToUpdate['monthly_speaking_attended_flg'] = 0;
35076                        }
35077                        if (!in_array($monthly_speaking_business_attended_flg, $userTestMonthFlag)) {
35078                            $fieldsToUpdate['monthly_speaking_business_attended_flg'] = 0;
35079                        }
35080
35081                        if ($fieldsToUpdate) {
35082                            $this->User->validate = array();
35083                            if (!$this->User->read(null, $userData['User']['id'])) {
35084                                $this->log(__METHOD__ . ' [NC-7779] User id does not exist. ' . json_encode($userData), $logFileName);
35085                                $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'User id does not exist', $userData);
35086                                $dataSource->rollback();
35087                                $dataSource->commit();
35088                                return ;
35089                            }
35090                            $this->User->set($fieldsToUpdate);
35091                            if (!$this->User->save()) {
35092                                $this->log(__METHOD__ . ' [NC-7779] Failed update user monthly_speaking_attended_flg or monthly_speaking_business_attended_flg to 0. ' . json_encode($data), $logFileName);
35093                                $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed update user monthly_speaking_attended_flg to 0', $data);
35094                                $dataSource->rollback();
35095                                $dataSource->commit();
35096                                return ;
35097                            }
35098                        }
35099                    }
35100                }
35101            }
35102
35103            $annualDiscountOption = isset($ptPaymentParams['annualDiscountOption']) ? $ptPaymentParams['annualDiscountOption'] : [];
35104            // if user cancel annual discount option
35105            if (
35106                $annualDiscountOption &&
35107                isset($annualDiscountOption['cancellation_fee']) &&
35108                $formType == Configure::read('payment_halfway_termination_of_annual_discount_option')
35109            ) {
35110                $doshData = [
35111                    'user_id' => $userId,
35112                    'discount_option_term_id' => $annualDiscountOption['discount_option_term_id'],
35113                    'discount_option_id' => $annualDiscountOption['discount_option_id'],
35114                    'discount_option_price_id' => $annualDiscountOption['discount_option_price_id'],
35115                    'payment_id' => $paymentSaveID,
35116                    'event' => $annualDiscountOption['dosh_event'],
35117                    'amount' => $annualDiscountOption['cancellation_fee'],
35118                    'currency_code' => $currencyCode,
35119                    'type' => $annualDiscountOption['dosh_type'],
35120                    'status' => $annualDiscountOption['dosh_status'],
35121                    'settlement_status' => 1 // success
35122                ];
35123
35124                // create discount option settlement history
35125                if (!$res = $this->DiscountOptionsSettlementHistory->createHistory($doshData)) {
35126                    $this->log(__METHOD__ . ' Failed to create discount option settlement history. ' . json_encode($doshData), $logFileName);
35127                    $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to create discount option settlement history. ', $doshData);
35128                    $dataSource->rollback();
35129                    $dataSource->commit();
35130                    return ;
35131                }
35132
35133                // stop user annual discount option term
35134                if (!$this->UserDiscountOptionsTerm->stopTerm(['userId' => $userId])) {
35135                    $this->log(__METHOD__ . ' Failed to stop annual discount option term. ' . json_encode(['userId' => $userId]), $logFileName);
35136                    $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to stop annual discount option term.', ['userId' => $userId]);
35137                    $dataSource->rollback();
35138                    $dataSource->commit();
35139                    return ;
35140                }
35141
35142                // update user memo
35143                $memo = date('Y/m/d H:i') . " 年間割引オプション解約\n" . $userData['User']['memo'];
35144                if (!$this->User->updateUserById(['userData' => ['memo' => $memo], 'id' => $userId])) {
35145                    $this->log(__METHOD__ . ' Failed to update user memo. ' . json_encode($memo) . ' id: ' . json_encode($userId), $logFileName);
35146                    $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to stop annual discount option term.', [$memo]);
35147                    $dataSource->rollback();
35148                    $dataSource->commit();
35149                    return ;
35150                }
35151                
35152                $adoLogParams = [
35153                    'user_id' => $userId,
35154                    'platform' => $platform,
35155                    'status' => 1, // subscribe
35156                    'controller_name' => $this->request->params['controller'],
35157                    'action_name' => $this->request->params['action'],
35158                    'user_type' => 0, // normal user
35159                    'option_before' => 1,
35160                    'option_after' => '',
35161                    'option_before_name' => 'Annual Discount Option',
35162                    'option_after_name' => '',
35163                    'option_type' => 3, // annual discount option
35164                    'payment_plan_id' => $paymentPlanId
35165                ];
35166
35167                if (!$this->UserOptionChangeLog->saveOptionChangeLog($adoLogParams)) {
35168                    $this->log(__METHOD__ . ' Failed to update option change. ' . json_encode($adoLogParams), $logFileName);
35169                    $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'Failed to update user data', $adoLogParams);
35170                    $dataSource->rollback();
35171                    $dataSource->commit();
35172                    return ;
35173                }
35174            }
35175
35176            // if payment was saved, and form type belongs to textbook purchase,
35177            // update textbook_sales table, insert payment_id
35178            if ($formType == Configure::read('payment_credit_textbook_purchase')) {
35179                // set textbook sales info
35180                $textbookSales = $this->TextbookSale->find('first', array(
35181                    'conditions' => array(
35182                        'TextbookSale.sales_code' => $ptPassword
35183                    ),
35184                    'recursive' => -1
35185                ));
35186                
35187                // if has textbook sales, update payment_id
35188                if ($textbookSales) {
35189                    $this->TextbookSale->clear();
35190                    if (!$this->TextbookSale->read(null, $textbookSales['TextbookSale']['id'])) {
35191                        $this->log(__METHOD__ . ' Textbook sales id does not exist. ' . json_encode($textbookSales), $logFileName);
35192                        $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'Textbook sales id does not exist', $textbookSales);
35193                        $dataSource->rollback();
35194                        $dataSource->commit();
35195                        return ;
35196                    }
35197                    $this->TextbookSale->set('payment_id', $this->Payment->id);
35198                    $this->TextbookSale->set('payment_status', 1);
35199                    if (!$this->TextbookSale->save()) {
35200                        $this->log(__METHOD__ . ' Failed update textbook sales payment status to 1. ' . json_encode($textbookSales), $logFileName);
35201                        $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'Failed update textbook sales payment status to 1', $textbookSales);
35202                        $dataSource->rollback();
35203                        $dataSource->commit();
35204                        return ;
35205                    }
35206                }
35207            }
35208
35209            // [STRIPE] check if receivable payment sent was either
35210            // receivable payment, monthly payment, force settlement, or retry payment
35211            // if yes, set receivable payments to "received"
35212            if (
35213                in_array($formType, array(
35214                    Configure::read('payment_credit_appreciation_receivable'),
35215                    Configure::read('payment_credit_receivable'),
35216                    Configure::read('payment_credit_monthly_payment'),
35217                    Configure::read('payment_credit_force_charge'),
35218                    Configure::read('payment_credit_retry'),
35219                    Configure::read('payment_credit_family_monthly_payment'),
35220                    Configure::read('payment_lite_credit_monthly_payment'),
35221                    Configure::read('payment_lite_credit_paid'),
35222                    Configure::read('payment_lite_plan_downgrade'),
35223                    Configure::read('payment_lite_plan_upgrade'),
35224                    Configure::read('payment_credit_change')
35225                ))
35226            ) {
35227                // get current payment_id
35228                $paymentID = $this->Payment->id;
35229
35230                // create new payment receivable
35231                if ($formType != Configure::read('payment_credit_receivable') && $receivablePayment) {
35232                    // set payment id
35233                    $data["payment_id"] = $paymentID;
35234
35235                    $paymentData = array(
35236                        'user_id' => $userId,
35237                        'amount' => $receivablePayment,
35238                        'status' => 1,
35239                        'type_id' => 1,
35240                        'reference_id' => $referenceId,
35241                        'card_company' => $card_company,
35242                        'param1' => json_encode($data),
35243                        'form_type' => Configure::read('payment_credit_receivable'),
35244                        'ordd' => $data["ordd"],
35245                        'currency_code' => $currencyCode, // set currency id to jpy
35246                        'transaction_code' => $paymentHash,
35247                        'price_id' => $priceId,
35248                        'payment_id' => $paymentPlanId,
35249                        'payment_type' => $paymentType,
35250                        'discounted_amount' => 0
35251                    );
35252
35253                    // create new payment
35254                    $this->Payment->clear();
35255                    $this->Payment->create();
35256                    $this->Payment->set($paymentData);
35257                    if (!$this->Payment->save()) {
35258                        $this->log(__METHOD__ . ' Failed to save payment data' . json_encode($paymentData), $logFileName);
35259                        $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data', $paymentData);
35260                        $dataSource->rollback();
35261                        $dataSource->commit();
35262                        return ;
35263                    }
35264
35265                    //update/add user`s settlement amount
35266                    $this->User->updateUserPayments($paymentData);
35267                    // set payment_id
35268                    $paymentID = $this->Payment->id;
35269
35270                }
35271
35272                // set payment receivable statuses to 2 - received
35273                $this->PaymentReceivable->updateReceivableReservationPayment(
35274                    $userData['User']['id'], 
35275                    array(
35276                        'status' => 2,
35277                        'payment_id' => $paymentID,
35278                        'payment_collection_date' => date("Y-m-d H:i:s"),
35279                        'card_company' => $card_company,
35280                        'payment_plan_id' => $paymentPlanId,
35281                        'membership_type_index' => $membershipStatusIndex
35282                    ),
35283                    array(
35284                        'PaymentReceivable.user_id' => $userData['User']['id'],
35285                        'PaymentReceivable.status' => 0,
35286                        'PaymentReceivable.payment_element_type' => 1,
35287                        'PaymentReceivable.created <=' => $cronDateRun
35288                    )
35289                );
35290
35291                // debug log
35292                $this->log("[STRIPEPAY_RECEIVABLE] kickback was recieved -> " . json_encode($data), $logFileName);
35293
35294                // create new payment for appreciation receivable
35295                if ($formType != Configure::read('payment_credit_appreciation_receivable') && $appreciationReceivable > 0) {
35296                    // set payment id
35297                    $data["payment_id"] = $paymentID;
35298                    //reset payment data
35299                    $paymentData = array();
35300
35301                    //set payment data
35302                    $paymentData = array(
35303                        'user_id' => $userId,
35304                        'amount' => $appreciationReceivable,
35305                        'status' => 1,
35306                        'type_id' => 1,
35307                        'reference_id' => $referenceId,
35308                        'card_company' => $card_company,
35309                        'param1' => json_encode($data),
35310                        'form_type' => Configure::read('appreciation_data.payment_form_type'),
35311                        'ordd' => $data["ordd"],
35312                        'currency_code' => $currencyCode, // set currency id to jpy
35313                        'transaction_code' => $paymentHash,
35314                        'price_id' => $priceId,
35315                        'payment_id' => $paymentPlanId,
35316                        'payment_type' => $paymentType,
35317                        'discounted_amount' => 0
35318                    );
35319
35320                    // create new payment
35321                    $this->Payment->clear();
35322                    $this->Payment->create();
35323                    $this->Payment->set($paymentData);
35324                    if (!$this->Payment->save()) {
35325                        $this->log(__METHOD__ . ' Failed to save appreciationReceivable payment data' . json_encode($paymentData), $logFileName);
35326                        $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save appreciationReceivable payment data', $paymentData);
35327                        $dataSource->rollback();
35328                        $dataSource->commit();
35329                        return ;
35330                    }
35331                    //update/add user`s settlement amount
35332                    $this->User->updateUserPayments($paymentData);
35333                    // set payment_id
35334                    $paymentID = $this->Payment->id;
35335
35336                }
35337
35338                // set payment receivable for appreciation statuses to 2 - received
35339                $this->PaymentReceivable->updateReceivableReservationPayment(
35340                    $userData['User']['id'], 
35341                    array(
35342                        'status' => 2,
35343                        'payment_id' => $paymentID,
35344                        'payment_collection_date' => date("Y-m-d H:i:s"),
35345                        'card_company' => $card_company,
35346                        'payment_plan_id' => $paymentPlanId,
35347                        'membership_type_index' => $membershipStatusIndex
35348                    ),
35349                    array(
35350                        'PaymentReceivable.user_id' => $userData['User']['id'],
35351                        'PaymentReceivable.status' => 0,
35352                        'PaymentReceivable.payment_element_type' => Configure::read('appreciation_data.payment_element_type'),
35353                        'PaymentReceivable.created <=' => $cronDateRun
35354                    )
35355                );
35356
35357                // debug log
35358                $this->log("[STIPEPAY_APPRECIATION_RECEIVABLE] kickback was recieved -> " . json_encode($data), $logFileName);
35359
35360                // create new payment for live lesson receivable
35361                if ($formType != Configure::read('payment_live_lesson_receivable') && $liveLessonReceivable) {
35362                    // set payment id
35363                    $data["payment_id"] = $paymentID;
35364
35365                    $paymentData = array(
35366                        'user_id' => $userId,
35367                        'amount' => $liveLessonReceivable,
35368                        'status' => 1,
35369                        'type_id' => 1,
35370                        'reference_id' => $referenceId,
35371                        'card_company' => $card_company,
35372                        'param1' => json_encode($data),
35373                        'form_type' => Configure::read('payment_live_lesson_receivable'),
35374                        'ordd' => $data["ordd"],
35375                        'currency_code' => $currencyCode, // set currency id to jpy
35376                        'transaction_code' => $paymentHash,
35377                        'price_id' => $priceId,
35378                        'payment_id' => $paymentPlanId,
35379                        'payment_type' => $paymentType,
35380                        'discounted_amount' => 0
35381                    );
35382
35383                    // create new payment
35384                    $this->Payment->clear();
35385                    $this->Payment->create();
35386                    $this->Payment->set($paymentData);
35387                    if (!$this->Payment->save()) {
35388                        $this->log(__METHOD__ . ' Failed to save payment data' . json_encode($paymentData), $logFileName);
35389                        $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data', $paymentData);
35390                        $dataSource->rollback();
35391                        $dataSource->commit();
35392                        return ;
35393                    }
35394                    //update/add user`s settlement amount
35395                    $this->User->updateUserPayments($paymentData);
35396                    // set payment_id
35397                    $paymentID = $this->Payment->id;
35398                }
35399
35400                // set payment receivable for live lesson statuses to 2 - received
35401                $this->PaymentReceivable->updateReceivableReservationPayment(
35402                    $userData['User']['id'], 
35403                    array(
35404                        'status' => 2,
35405                        'payment_id' => $paymentID,
35406                        'payment_collection_date' => date("Y-m-d H:i:s"),
35407                        'card_company' => $card_company,
35408                        'payment_plan_id' => $paymentPlanId,
35409                        'membership_type_index' => $membershipStatusIndex
35410                    ),
35411                    array(
35412                        'PaymentReceivable.user_id' => $userData['User']['id'],
35413                        'PaymentReceivable.status' => 0,
35414                        'PaymentReceivable.payment_element_type' => Configure::read('payment_element_type.live'),
35415                        'PaymentReceivable.created <=' => $cronDateRun
35416                    )
35417                );
35418                
35419                // debug log
35420                $this->log("[STRIPEPAY_LIVE_RECEIVABLE] kickback was recieved -> " . json_encode($data), $logFileName);                
35421
35422            }
35423
35424            // NJ-63985
35425            if (!empty($ptPaymentParams['monthlyDiscount']) && !empty($ptPaymentParams['monthly_grp_id'])) {
35426                $requestCouponConfirmData = array(
35427                    'grpId' => $ptPaymentParams['monthly_grp_id'],
35428                    'paymentId' => $paymentSaveID
35429                );
35430
35431                $result_confirm = $this->UsersCouponV1->performCouponConfirm($requestCouponConfirmData);
35432
35433                if (!$result_confirm) {
35434                    $this->log(__METHOD__ . ' Failed to update used coupons.' . json_encode($ucData), $logFileName);
35435                    $this->log(__METHOD__ . ' Failed to update used coupons.' . json_encode($ucData), 'error');
35436                    $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update used coupons.', $ucData);
35437                    $dataSource->rollback();
35438                    $dataSource->commit();
35439                    return ;
35440                }
35441            }
35442
35443            // NC-7029: CHECK REFERRAL USER
35444            if (
35445                in_array($formType, array(
35446                    Configure::read('payment_credit_monthly_payment'),
35447                    Configure::read('payment_credit_force_charge'),
35448                    Configure::read('payment_credit_retry'),
35449                    Configure::read('payment_credit_authentication'),
35450                    Configure::read('payment_credit_family_monthly_payment'),
35451                    Configure::read('payment_lite_credit_monthly_payment'),
35452                    Configure::read('payment_lite_credit_paid')
35453                ))
35454            ) {
35455                $ruData = array(
35456                    'referee_id' => $userData['User']['id'],
35457                    'payment_plan_id' => $newYear95percentOffCampaign ? Configure::read('payment_plans.free_trial') : $paymentPlanId,
35458                    'currency_code' => $userData['User']['currency_code'],
35459                    'logFileName' => $logFileName,
35460                    'form_type' => $newYear95percentOffCampaign ? Configure::read('payment_credit_authentication') : $formType
35461                );
35462
35463                $couponReferredData = $this->UsersReferral->checkReferredUser($ruData);
35464                if (isset($couponReferredData['error']) && $couponReferredData['error']) {
35465                    $this->log(__METHOD__ . ' Failed to update users referral event flg.' . json_encode($ruData), $logFileName);
35466                    $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to update users referral event flg.', $ruData);
35467                    $dataSource->rollback();
35468                    $dataSource->commit();
35469                    return ;
35470                }
35471
35472                $couponMailId = Configure::read('site_in_mail.coupon_mail_template_id');
35473
35474                // send coupon mail to referee
35475                if (isset($couponReferredData['sendMailToReferee']) && $couponReferredData['sendMailToReferee']) {
35476                    $refereeData = array(
35477                        'id' => $userData['User']['id'],
35478                        'email' => $userData['User']['email'],
35479                        'native_language2' => $userData['User']['native_language2'],
35480                        'hash' => $userData['User']['hash'],
35481                        'refereeName' => $userData['User']['nickname'],
35482                        'referrerName' => $couponReferredData['referrerName'],
35483                        'couponAmount' => $couponReferredData['refereeSaveAmount'],
35484                        'couponUpdatedTotal' => $couponReferredData['refereeUpdatedTotal']
35485                    );
35486
35487                    // send mail to referee
35488                    myMailer::sendTemplateMail($couponMailId, $userData['User']['email'], $refereeData, array(), 'User');
35489                }
35490
35491                // send coupon mail to referer
35492                if (isset($couponReferredData['sendMailToReferer']) && $couponReferredData['sendMailToReferer']) {
35493                    $referrerData = array(
35494                        'id' => $couponReferredData['referrerId'],
35495                        'email' => $couponReferredData['referrerEmail'],
35496                        'native_language2' => $couponReferredData['nativeLanguage2'],
35497                        'hash' => $couponReferredData['referrerHash'],
35498                        'refereeName' => $userData['User']['nickname'],
35499                        'referrerName' => $couponReferredData['referrerName'],
35500                        'couponAmount' => $couponReferredData['refererSaveAmount'],
35501                        'couponUpdatedTotal' => $couponReferredData['refererUpdatedTotal']
35502                    );
35503
35504                    // send mail to referrer
35505                    myMailer::sendTemplateMail($couponMailId, $couponReferredData['referrerEmail'], $referrerData, array(), 'User');
35506                }
35507
35508                
35509                if ( //Amazon gift campaign
35510                    in_array($formType, array(
35511                        Configure::read('payment_credit_force_charge'),
35512                        Configure::read('payment_credit_authentication')
35513                    ))
35514                ) {
35515                    ClassRegistry::init('CampaignSettingTable')->amazonGift(array('user_id' => $userData['User']['id'], 'type' => 1));
35516                }
35517            }
35518                    
35519            // NJ-47740
35520            $getCouponDiscounDetail = PaymentTable::getCouponDiscountRequestDetail($ptPaymentParams, 'native');
35521            $nativeOptionDiscount = !empty($getCouponDiscounDetail['discounted_amount']) ? $getCouponDiscounDetail['discounted_amount'] : 0;
35522            $nativeCouponRequestId = !empty($getCouponDiscounDetail['coupon_request_id']) ? $getCouponDiscounDetail['coupon_request_id'] : null;
35523            // if has native speaker payment
35524            if (
35525                isset($ptPaymentParams['nativeOptionPayment']) && ($ptPaymentParams['nativeOptionPayment'] > 0 || $nativeOptionDiscount > 0)
35526                && in_array($ptPaymentParams['formType'], array(Configure::read('payment_credit_monthly_payment'), Configure::read('payment_credit_family_monthly_payment')))
35527            ) {
35528                $nspFormType = Configure::read('payment_native_option_monthly_payment');
35529                if (isset($ptPaymentParams['nativeOptionJoin']) && $ptPaymentParams['nativeOptionJoin']) {
35530                    $nspFormType = Configure::read('payment_native_option_join');
35531                }
35532                
35533                // check if family plan
35534                if ($familyId) {
35535                    // change reference id to parent id
35536                    $referenceId = isset($data['sendid']) ? $data['sendid'] : 0;
35537                } else {
35538                    $referenceId = $userId;
35539                }
35540
35541                $paymentData = array(
35542                    'user_id' => $userId,
35543                    'amount' => $ptPaymentParams['nativeOptionPayment'],
35544                    'status' => 1,
35545                    'type_id' => 1,
35546                    'reference_id' => $referenceId,
35547                    'payment_transaction_password' => $ptPassword,
35548                    'card_company' => $card_company,
35549                    'param1' => json_encode($data),
35550                    'form_type' => $nspFormType,
35551                    'ordd' => $data["ordd"],
35552                    'currency_code' => $currencyCode,
35553                    'transaction_code' => $paymentHash,
35554                    'price_id' => $priceId,
35555                    'payment_id' => $paymentPlanId,
35556                    'payment_type' => Configure::read('payment_types.native_option')
35557                );
35558
35559                // NJ-47740
35560                $paymentData['discounted_amount'] = $nativeOptionDiscount;
35561                $paymentData['coupon_request_id'] = $nativeCouponRequestId;
35562
35563                // create new payment
35564                $this->Payment->clear();
35565                $this->Payment->create();
35566                $this->Payment->set($paymentData);
35567                if (!$this->Payment->save()) {
35568                    $this->log(__METHOD__ . ' Failed to save payment data' . json_encode($paymentData), $logFileName);
35569                    $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data', $paymentData);
35570                    $dataSource->rollback();
35571                    return ;
35572                }
35573                
35574                //update/add user`s settlement amount
35575                $this->User->updateUserPayments($paymentData);
35576
35577                // NJ-47740
35578                if (!empty($paymentData['coupon_request_id']) && $paymentData['discounted_amount'] > 0) {
35579                    // confirm coupon use request for native discount
35580                    $requestCouponConfirmData = array(
35581                        'grpId' => $paymentData['coupon_request_id'],
35582                        'paymentId' => $this->Payment->id
35583                    );
35584                    $result_confirm = $this->UsersCouponV1->performCouponConfirm($requestCouponConfirmData);
35585                    
35586                    if (!$result_confirm) {
35587                        $this->log(__METHOD__ . ' Failed to confirm native coupon use request. ' . json_encode($requestCouponConfirmData) . ' -- ' . json_encode($data), $logFileName);
35588                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to confirm native coupon use request', $data, $requestCouponConfirmData);
35589                        return ;
35590                    }
35591                }
35592                // NJ-47740 end
35593                
35594                // update payment details
35595                $updatePaymentDetailParams = array(
35596                    'currencyCode' => $paymentData['currency_code'],
35597                    'formType' => $paymentData['form_type'],
35598                    'paymentType' => $paymentData['payment_type'],
35599                    'amount' => $paymentData['amount'],
35600                    'discounted_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0,
35601                    'familyId' => $familyId,
35602                    'cronDateRun' => $cronDateRun,
35603                    'priceId' => $paymentData['price_id'],
35604                    'paymentPlanId' => $paymentData['payment_id'],
35605                    'user_id' => $paymentData['user_id'],
35606                    'coupon_use_request_id' => isset($paymentData['coupon_request_id']) ? $paymentData['coupon_request_id'] : null,
35607                    'coupon_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0
35608                );
35609                
35610                $updatePaymentDetail = array(
35611                    'id' => $ptId,
35612                    'fields' => array(
35613                        'payment_details' => $updatePaymentDetailParams
35614                    )
35615                );
35616
35617                if (!$this->PaymentTransaction->updateWPPaymentTransaction($updatePaymentDetail)) {
35618                    $this->log(__METHOD__ . ' Failed to update payment details. ' . json_encode($updatePaymentDetail), $logFileName);
35619                }
35620            }
35621
35622            // if has callan option payment
35623            // NJ-47740
35624            $getCouponDiscounDetail = PaymentTable::getCouponDiscountRequestDetail($ptPaymentParams, 'callan');
35625            $callanOptionDiscount = !empty($getCouponDiscounDetail['discounted_amount']) ? $getCouponDiscounDetail['discounted_amount'] : 0;
35626            $callanCouponRequestId = !empty($getCouponDiscounDetail['coupon_request_id']) ? $getCouponDiscounDetail['coupon_request_id'] : null;
35627            // if has callan option payment
35628            if (
35629                isset($ptPaymentParams['callanOptionPayment']) && ($ptPaymentParams['callanOptionPayment'] > 0 || $callanOptionDiscount > 0)
35630                && in_array($ptPaymentParams['formType'], array(Configure::read('payment_credit_monthly_payment'), Configure::read('payment_credit_family_monthly_payment')))
35631            ) {
35632                $nspFormType = Configure::read('payment_callan_option_monthly_payment');
35633                if (isset($ptPaymentParams['callanOptionJoin']) && $ptPaymentParams['callanOptionJoin']) {
35634                    $nspFormType = Configure::read('payment_callan_option_join');
35635                }
35636                
35637                // check if family plan
35638                if ($familyId) {
35639                    // change reference id to parent id
35640                    $referenceId = isset($data['sendid']) ? $data['sendid'] : 0;
35641                } else {
35642                    $referenceId = $userId;
35643                }
35644
35645                $paymentData = array(
35646                    'user_id' => $userId,
35647                    'amount' => $ptPaymentParams['callanOptionPayment'],
35648                    'status' => 1,
35649                    'type_id' => 1,
35650                    'reference_id' => $referenceId,
35651                    'payment_transaction_password' => $ptPassword,
35652                    'card_company' => $card_company,
35653                    'param1' => json_encode($data),
35654                    'form_type' => $nspFormType,
35655                    'ordd' => $data["ordd"],
35656                    'currency_code' => $currencyCode,
35657                    'transaction_code' => $paymentHash,
35658                    'price_id' => $priceId,
35659                    'payment_id' => $paymentPlanId,
35660                    'payment_type' => Configure::read('payment_types.callan_option')
35661                );
35662                
35663                // NJ-47740
35664                $paymentData['discounted_amount'] = $callanOptionDiscount;
35665                $paymentData['coupon_request_id'] = $callanCouponRequestId;
35666
35667                // create new payment
35668                $this->Payment->clear();
35669                $this->Payment->create();
35670                $this->Payment->set($paymentData);
35671                if (!$this->Payment->save()) {
35672                    $this->log(__METHOD__ . ' Failed to save payment data' . json_encode($paymentData), $logFileName);
35673                    $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to save payment data', $paymentData);
35674                    $dataSource->rollback();
35675                    return ;
35676                }
35677                
35678                //update/add user`s settlement amount
35679                $this->User->updateUserPayments($paymentData);
35680
35681                // NJ-47740
35682                if (!empty($paymentData['coupon_request_id']) && $paymentData['discounted_amount'] > 0) {
35683                    // confirm coupon use request for callan discount
35684                    $requestCouponConfirmData = array(
35685                        'grpId' => $paymentData['coupon_request_id'],
35686                        'paymentId' => $this->Payment->id
35687                    );
35688                    $result_confirm = $this->UsersCouponV1->performCouponConfirm($requestCouponConfirmData);
35689
35690                    if (!$result_confirm) {
35691                        $this->log(__METHOD__ . ' Failed to confirm callan coupon use request. ' . json_encode($requestCouponConfirmData) . ' -- ' . json_encode($data), $logFileName);
35692                        $this->slackZeusErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, 'Failed to confirm callan coupon use request', $data, $requestCouponConfirmData);
35693                        return;
35694                    }
35695                }
35696                // NJ-47740 end
35697                
35698                // update payment details
35699                $updatePaymentDetailParams = array(
35700                    'currencyCode' => $paymentData['currency_code'],
35701                    'formType' => $paymentData['form_type'],
35702                    'paymentType' => $paymentData['payment_type'],
35703                    'amount' => $paymentData['amount'],
35704                    'discounted_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0,
35705                    'familyId' => $familyId,
35706                    'cronDateRun' => $cronDateRun,
35707                    'priceId' => $paymentData['price_id'],
35708                    'paymentPlanId' => $paymentData['payment_id'],
35709                    'user_id' => $paymentData['user_id'],
35710                    'coupon_use_request_id' => isset($paymentData['coupon_request_id']) ? $paymentData['coupon_request_id'] : null,
35711                    'coupon_amount' => isset($paymentData['discounted_amount']) ? $paymentData['discounted_amount'] : 0
35712                );
35713                
35714                $updatePaymentDetail = array(
35715                    'id' => $ptId,
35716                    'fields' => array(
35717                        'payment_details' => $updatePaymentDetailParams
35718                    )
35719                );
35720
35721                if (!$this->PaymentTransaction->updateWPPaymentTransaction($updatePaymentDetail)) {
35722                    $this->log(__METHOD__ . ' Failed to update payment details. ' . json_encode($updatePaymentDetail), $logFileName);
35723                }
35724            }
35725            
35726            // activate the user native option (new, resume, and monthly payment)
35727            if (isset($ptPaymentParams['nativeOptionPayment']) && ($ptPaymentParams['nativeOptionPayment'] > 0 || $nativeOptionDiscount > 0)) { 
35728
35729                $this->log(__METHOD__ . ' NJ-2388 debug Payment Transaction Data: ' . json_encode($ptData), 'native_option_debug');
35730
35731                // - option process data
35732                $optionProcessData = array(
35733                    'user_id' => $userId,
35734                    'type' => 'on',
35735                    'option_type' => Configure::read('native_speaker.options.all_you_can_eat')
35736                );
35737
35738                $this->User->userNativeOptionProcess($optionProcessData);
35739
35740                //NJ-2814 add logs
35741                if (isset($ptPaymentParams['nativeOptionJoin']) && $ptPaymentParams['nativeOptionJoin']) {
35742                    $nativeStatus = 1; // subscribed
35743                    $statusBefore = '';
35744                } else {
35745                    $nativeStatus = 2; // Monthly Continue
35746                    $statusBefore = 1;
35747                }
35748
35749                $optionAfterName = 'Native Unlimited Option';
35750
35751                $optionLogParams = array(
35752                    'user_id' => $userId,
35753                    'platform' => $ptPaymentParams['platform'],
35754                    'status' => $nativeStatus,
35755                    'controller_name' => $this->request->params['controller'],
35756                    'action_name' => $this->request->params['action'],
35757                    'user_type' => 0, // user
35758                    'option_before' => $statusBefore,
35759                    'option_after' => 1,
35760                    'option_before_name' => '',
35761                    'option_after_name' => $optionAfterName,
35762                    'option_type' => 1,
35763                    'payment_plan_id' => $paymentPlanId
35764                );
35765
35766                ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
35767
35768                // - save registration status step
35769                $stepKey = Configure::read('registration_steps.user_info_entry');
35770                $this->saveStep($userId, $stepKey);
35771            }
35772
35773            // activate the user native option (new, resume, and monthly payment)
35774            if (isset($ptPaymentParams['callanOptionPayment']) && ($ptPaymentParams['callanOptionPayment'] > 0 || $callanOptionDiscount > 0)) { 
35775
35776                $this->log(__METHOD__ . ' NJ-2388 debug Payment Transaction Data: ' . json_encode($ptData), 'native_option_debug');
35777
35778                // - option process data
35779                $optionProcessData = array(
35780                    'user_id' => $userId,
35781                    'type' => 'on',
35782                    'option_type' => Configure::read('callan_unlimited.options.callan_unlimited_option')
35783                );
35784
35785                $this->User->userNativeOptionProcess($optionProcessData);
35786
35787                //NJ-2814 add logs
35788                if (isset($ptPaymentParams['callanOptionJoin']) && $ptPaymentParams['callanOptionJoin']) {
35789                    $nativeStatus = 1; // subscribed
35790                    $statusBefore = '';
35791                } else {
35792                    $nativeStatus = 2; // Monthly Continue
35793                    $statusBefore = 1;
35794                }
35795                $optionAfterName = 'Callan Unlimited Option';
35796                $optionLogParams = array(
35797                    'user_id' => $userId,
35798                    'platform' => $ptPaymentParams['platform'],
35799                    'status' => $nativeStatus,
35800                    'controller_name' => $this->request->params['controller'],
35801                    'action_name' => $this->request->params['action'],
35802                    'user_type' => 0, // user
35803                    'option_before' => $statusBefore,
35804                    'option_after' => 1,
35805                    'option_before_name' => '',
35806                    'option_after_name' => $optionAfterName,
35807                    'option_type' => 2,
35808                    'payment_plan_id' => $paymentPlanId
35809                );
35810
35811                ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
35812            }
35813
35814            // if parent user update children's card company
35815            if ($formType == Configure::read('payment_credit_change')) {
35816                $childList = $this->User->getChildId($userId);
35817
35818                // check if user is parent
35819                if (!empty($childList)) {
35820                    foreach ($childList as $childId) {
35821                        $this->User->clear();
35822                        $updateCCArr = array('card_company' => $card_company);
35823
35824                        //Update also child card exp date same with parent
35825                        if (isset($ptPaymentParams['cardExpirationDate'])) {
35826                            $updateCCArr['card_expiration_date'] = $ptPaymentParams['cardExpirationDate'];
35827                        }
35828
35829                        if (!$this->User->read(array_keys($updateCCArr), $childId)) {
35830                            $this->log(__METHOD__ . ' child id does not exist. ' . json_encode($updateCCArr) . ' parent id --> ' . json_encode($userId), $logFileName);
35831                            $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'child id does not exist.', $updateCCArr);
35832                            $dataSource->rollback();
35833                            $dataSource->commit();
35834                            return ;
35835                        }
35836
35837                        $this->User->set($updateCCArr);
35838                        if (!$this->User->save()) {
35839                            $this->log(__METHOD__ . ' failed to update child card company. ' . json_encode($updateCCArr) . ' parent id --> ' . json_encode($userId), $logFileName);
35840                            $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'failed to update child card company.', $updateCCArr);
35841                            $dataSource->rollback();
35842                            $dataSource->commit();
35843                            return ;
35844                        }
35845                    }
35846                }
35847            }
35848
35849            // if light plan
35850            if ($formType == Configure::read('payment_lite_plan_upgrade') && $_allowChangePlan) {
35851                // check if user subscribed to zero student discount option
35852                $discountOptionData = $this->UserDiscountOptionsTerm->getTerm([
35853                    'user_id' =>  $userId,
35854                    'discount_option_id' => Configure::read('discount_option.zero_student.plan_id'),
35855                    'status' => 1
35856                ]);
35857
35858                // stop discount option
35859                if ($discountOptionData) {
35860                    // count successful discount
35861                    $discountCount = $this->DiscountOptionsSettlementHistory->countSuccessfulDiscount($discountOptionData['discount_option_term_id']);
35862                    
35863                    // open tunnel
35864                    myTools::initializeApiTunnel(['DiscountOptionController']);
35865
35866                    // initialize controller
35867                    $doc = new DiscountOptionController();
35868
35869                    $doshStatus = $discountCount ?
35870                        Configure::read('discount_option.dosh_status.midterm_cancellation') :
35871                        Configure::read('discount_option.dosh_status.maturity_cancellation');
35872
35873                    $szsdoParams = [
35874                        'discountOptionId' => $discountOptionData['discount_option_id'],
35875                        'discountOptionPriceId' => $discountOptionData['discount_option_price_id'],
35876                        'termId' => $discountOptionData['discount_option_term_id'],
35877                        'cancellationFee' => 0,
35878                        'cancellationType' => Configure::read('discount_option.dosh_type.plan_change'),
35879                        'userData' => $userData['User'],
35880                        'fromController' => $this->request->params['controller'],
35881                        'fromAction' => $this->request->params['action'],
35882                        'doshStatus' => $doshStatus
35883                    ];
35884
35885                    // set data
35886                    $doc->params = $szsdoParams;
35887
35888                    // stop
35889                    $stopDiscountOption = json_decode($doc->stopDiscountOption(), true);
35890
35891                    if (isset($stopDiscountOption['error']) && $stopDiscountOption['error']) {
35892                        $this->log(__METHOD__ . 'failed to stop zero student discount option: '.json_encode($szsdoParams), 'family_plan');
35893                        $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'failed to stop zero student discount option.', $szsdoParams);
35894                        return ;
35895                    }
35896                }
35897            }
35898
35899            $ptStatus = 1; // success
35900
35901            $dataSource->commit();
35902
35903            // - NJ-31307 : trigger campaign
35904            if(!empty($ptPaymentParams['nativeOptionPayment']) || !empty($ptPaymentParams['callanOptionPayment'])){
35905                ClassRegistry::init('CampaignSettingTable')->callanUnlimitedCampaign(array(
35906                    'user_id' => $userId, 
35907                    'trigger' => 3, 
35908                    'pt_params' => $ptData ?? [],
35909                    'payment_type' => 'Zeuspay'
35910                ));
35911            }
35912
35913
35914        } else {
35915            # possible fail transactions
35916            $inViableFailTransactions = array(
35917                Configure::read('payment_credit_monthly_payment'),
35918                Configure::read('payment_credit_coin_purchase'),
35919                Configure::read('payment_credit_receivable'),
35920                Configure::read('payment_credit_family_monthly_payment'),
35921                Configure::read('payment_native_option_join'),
35922                Configure::read('payment_native_option_monthly_payment'),
35923                Configure::read('payment_callan_option_join'),
35924                Configure::read('payment_callan_option_monthly_payment'),
35925                Configure::read('payment_lite_credit_monthly_payment')
35926            );
35927
35928            # if the form type is a possible fail transaction
35929            if (in_array($formType, $inViableFailTransactions)) {
35930                // return if existing user or new user failed to become family plan paid user
35931                if (
35932                    $formType == Configure::read('payment_credit_family_monthly_payment') && $familyId &&
35933                    isset($ptPaymentParams['new_family_plan']) && $ptPaymentParams['new_family_plan']
35934                ) {
35935                    $this->log(__METHOD__ . 'zeus.error.ng_return_applying_family: '.json_encode($data), 'family_plan');
35936                    $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userId, 'failed to update child card company.', $updateCCArr);
35937                    return ;
35938                }
35939
35940                # if form_type is for monthly payment
35941                if (
35942                    Configure::read('payment_credit_monthly_payment') == $formType ||
35943                    Configure::read('payment_credit_family_monthly_payment') == $formType ||
35944                    Configure::read('payment_lite_credit_monthly_payment') == $formType
35945                ) {
35946                    # set user data
35947                    $this->User->validate = array();
35948                    $userPrevData = $this->User->read(null, $userData['User']['id']);
35949                    if (!$userPrevData) {
35950                        $this->log(__METHOD__ . ' User id does not exist. ' . json_encode($userData), $logFileName);
35951                        $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'User id does not exist', $userData);
35952                        return ;
35953                    }
35954
35955                    //update user memo && native option cancellation time
35956                    $date = date('Y/m/d H:i:s');
35957                    $memoStr = $date." Cancellation of Native Speaker Unlimited option";
35958                    $memoStr2 = $date." Cancellation of Callan Unlimited option";
35959                    $updatedMemo = $memoStr."\n".$memoStr2."\n".$userPrevData['User']['memo'];
35960                    $userUpdate = array(
35961                        'fail_flg' => '1',
35962                        'counseling_attended_flg' => '1',
35963                        'charge_flg' => '0',
35964                        'allow_appreciation_flg' => '0',
35965                        'show_appreciation_flg' => '0',
35966                        'native_option' => 0,
35967                        'callan_option' => 0,
35968                        'next_charge_date' => NULL,
35969                        'memo' => $updatedMemo
35970                    );
35971
35972                    if (isset($userPrevData['User']['native_option']) && $userPrevData['User']['native_option']) {
35973                        $userUpdate['native_option_cancellation_time'] = $date;
35974                    }
35975
35976                    if (isset($userPrevData['User']['callan_option']) && $userPrevData['User']['callan_option']) {
35977                        $userUpdate['callan_option_cancellation_time'] = $date;
35978                    }
35979
35980                    $this->User->set($userUpdate);
35981                    if (!$this->User->save()) {
35982                        $this->log(__METHOD__ . ' Failed to update user data. ' . json_encode($userUpdate), $logFileName);
35983                        $this->slackStripeErrorPostMsg('USER', __LINE__, __METHOD__, $userData['User']['id'], 'Failed to update user data', $userUpdate);
35984                        return ;
35985                    } else {
35986                        // check if has Native Option
35987                        if (isset($ptPaymentParams['nativeOptionPayment']) && $ptPaymentParams['nativeOptionPayment'] > 0) {
35988                            //NJ-2814 add logs
35989                            if (isset($ptPaymentParams['nativeOptionJoin']) && $ptPaymentParams['nativeOptionJoin']) {
35990                                $nativeStatus = 1; // subscribed
35991                                $statusBefore = $option_before_name = '';
35992                            } else {
35993                                $nativeStatus = 3; // unsubscribed
35994                                $statusBefore = 1;
35995                                $option_before_name = 'Native Unlimited Option';
35996                            }
35997
35998                            $optionLogParams = array(
35999                                'user_id' => $userId,
36000                                'platform' => $ptPaymentParams['platform'],
36001                                'status' => $nativeStatus,
36002                                'controller_name' => $this->request->params['controller'],
36003                                'action_name' => $this->request->params['action'],
36004                                'user_type' => 0, // user
36005                                'option_before' => $statusBefore,
36006                                'option_after' => 1,
36007                                'option_before_name' => $option_before_name,
36008                                'option_after_name' => '',
36009                                'option_type' => 1,
36010                                'payment_plan_id' => $paymentPlanId
36011                            );
36012
36013                            ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
36014                        }
36015
36016                        // check if has Callan Option
36017                        if (isset($ptPaymentParams['callanOptionPayment']) && $ptPaymentParams['callanOptionPayment'] > 0) {
36018                            //NJ-2814 add logs
36019                            if (isset($ptPaymentParams['callanOptionJoin']) && $ptPaymentParams['callanOptionJoin']) {
36020                                $callanStatus = 1; // subscribed
36021                                $statusBefore = $option_before_name = '';
36022                            } else {
36023                                $callanStatus = 3; // unsubscribed
36024                                $statusBefore = 1;
36025                                $option_before_name = 'Callan Unlimited Option';
36026                            }
36027
36028                            $optionLogParams = array(
36029                                'user_id' => $userId,
36030                                'platform' => $ptPaymentParams['platform'],
36031                                'status' => $callanStatus,
36032                                'controller_name' => $this->request->params['controller'],
36033                                'action_name' => $this->request->params['action'],
36034                                'user_type' => 0, // user
36035                                'option_before' => $statusBefore,
36036                                'option_after' => 1,
36037                                'option_before_name' => $option_before_name,
36038                                'option_after_name' => '',
36039                                'option_type' => 2,
36040                                'payment_plan_id' => $paymentPlanId
36041                            );
36042
36043                            ClassRegistry::init("UserOptionChangeLog")->saveOptionChangeLog($optionLogParams);
36044                        }
36045                    }
36046
36047                    # update user who join in ContinuationCampaign to fail status - 3
36048                    $this->ContinuationCampaign->setFailedUser(array(
36049                        'user_id' => $userData['User']['id']
36050                    ));
36051
36052                    // NJ-47740
36053                    // confiscate pending request coupon for native and callan option
36054                    $this->UsersCouponV1->confiscateOptionDiscount(array('userId' => $userId));
36055
36056                    // Get children list
36057                    $childList = $this->User->getChildId($userData['User']['id']);
36058
36059                    // check if user is parent 
36060                    if (!empty($childList)) {
36061                        foreach ($childList as $childId) {
36062                            // get child detail
36063                            $familyMember = $this->User->find('first', array(
36064                                'fields' => array(
36065                                    'User.id',
36066                                    'User.memo',
36067                                    'User.parent_id',
36068                                    'User.native_option',
36069                                    'User.callan_option'
36070                                ),
36071                                'conditions' => array('User.id' => $childId)
36072                            ));
36073                            $familyObj = new UserTable($familyMember['User']);
36074                            $addMemo = 'Family plan[User]: family deactivation parent failed settlement';
36075                            unset($familyObj->parent_id);
36076
36077                            // update children status to free
36078                            if ($this->User->updateStatusToFree($familyObj, $addMemo)) {
36079                                // - deactivate reserved lessons of the children
36080                                $this->LessonSchedule->deactivateDisableReservedLessons($childId, true, false, true, null, false, true);
36081
36082                                // NC-8645: add deactivation lock
36083                                UserTable::saveUserDeactivationLock($childId);
36084
36085                                // NC-5342: add deactivation log
36086                                $this->loadModel('FamilyDeactivationLog');
36087                                $this->FamilyDeactivationLog->addLog($childId);
36088                            }
36089
36090                            // NJ-47740
36091                            // confiscate pending request coupon for native and callan option
36092                            $this->UsersCouponV1->confiscateOptionDiscount(array('userId' => $childId));
36093                        }
36094                    }
36095                }
36096
36097                # set error code
36098                $data['error_code'] = Configure::read('zeus.error.ng_return');
36099                if (!$this->stripe_error_log_set($data, $ptPaymentParams)) {
36100                    $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, '_error_log_set failed', $data);
36101                    return ;
36102                }
36103            } else {
36104            }
36105
36106            if ($nativeOptionPayment > 0 && in_array($formType, array(Configure::read('payment_credit_monthly_payment'), Configure::read('payment_credit_family_monthly_payment')))) {
36107                $data['formType'] = Configure::read('payment_native_option_monthly_payment');
36108                $ptPaymentParams['paymentAmount'] = $nativeOptionPayment;
36109
36110                if (!$this->stripe_error_log_set($data, $ptPaymentParams)) {
36111                    $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, '_error_log_set failed', $data);
36112                    return ;
36113                }
36114            }
36115
36116            if ($callanOptionPayment > 0 && in_array($formType, array(Configure::read('payment_credit_monthly_payment'), Configure::read('payment_credit_family_monthly_payment')))) {
36117                $data['formType'] = Configure::read('payment_callan_option_monthly_payment');
36118                $ptPaymentParams['paymentAmount'] = $callanOptionPayment;
36119
36120                if (!$this->stripe_error_log_set($data, $ptPaymentParams)) {
36121                    $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, '_error_log_set failed', $data);
36122                    return ;
36123                }
36124            }
36125
36126            if (isset($ptPaymentParams['annualDiscountOption']) && $formType == Configure::read('payment_halfway_termination_of_annual_discount_option')) {
36127                if (!$this->stripe_error_log_set($data, $ptPaymentParams)) {
36128                    $this->slackStripeErrorPostMsg('PAYMENT', __LINE__, __METHOD__, $userId, '_error_log_set failed', $data);
36129                    return ;
36130                }
36131            }
36132
36133            if ($formType != Configure::read('payment_credit_authentication')) {
36134                $ptStatus = 2; // error;
36135            } else {
36136                $ptStatus = 0;
36137            }
36138        }
36139
36140        // update payment transaction
36141        $this->updatePaymentTransaction(array(
36142            'id' => $ptId,
36143            'fields' => array(
36144                'status' => $ptStatus,
36145                'response_text' => array('stripe_kickback' => $data)
36146            ),
36147            'logFileName' => $logFileName
36148        ));
36149
36150        // add registration bonus if user registration
36151        if (isset($ptPaymentParams['userRegister']) && $ptPaymentParams['userRegister']) {
36152
36153            if (isset($zeroStudentDiscount) && $zeroStudentDiscount) {
36154                UsersPointHistoryTable::checkDailyBonus($userId, true);
36155            } else {
36156                UsersPointHistoryTable::checkDailyBonus($userId);
36157            }
36158            if (
36159                (isset($ptPaymentParams['campaign95percentOff']) && $ptPaymentParams['campaign95percentOff'])
36160                || (time() >= strtotime(Configure::read('campaign_config.feb_new_registration.period.start')) && time() <= strtotime(Configure::read('campaign_config.feb_new_registration.period.end')))
36161            ) {
36162                $paramsRefBonus = array(
36163                    "type" => 1, // kickback
36164                    "userID" => $userId,
36165                    "userRegister" => true
36166                );
36167                // add referral coin NC-10009
36168                $this->User->addReferralBonus($paramsRefBonus);
36169            }
36170
36171            // - check if lite plan user 
36172            $this->User->clear();
36173            $_currentUser = $this->User->read(array('id','memo','payment_plan_id'), $userId);
36174            $_currentUserMemo = $_currentUser['User']['memo'];
36175
36176            if (in_array($_currentUser['User']['payment_plan_id'], Configure::read('lite_payment_plans'))) {
36177                # update user memo
36178                $_coins = Configure::read('credit.lite_plan_bonus_coin_authentication');
36179                if ($formType == Configure::read('payment_lite_credit_monthly_payment')) {
36180                    $_coins = Configure::read('lite_plan_monthly_coin');
36181                }
36182                $_dateNow = date('Y-m-d H:i:s');
36183                $_updateMemo =  "\n {$_dateNow} Light Plan Bonus: {$_coins}";
36184                $_updateMemo = $_updateMemo . "\n" . $_currentUserMemo;
36185
36186                // - update user memo 
36187                $this->User->clear();
36188                $memUpdateParams = array(
36189                    'id' => $userId,
36190                    'memo' => $_updateMemo
36191                );
36192                $this->User->set($memUpdateParams);
36193                $this->User->save();
36194            }
36195        }
36196
36197        // campaign master trigger 2
36198        if (
36199            strtoupper($data['result']) == 'OK' &&
36200            $formType == Configure::read('payment_credit_monthly_payment') && 
36201            $userData['User']['payment_plan_id'] == Configure::read('payment_plans.free_trial')
36202        ) {
36203            UsersPointTable::giveBonusCoins(['userId' => $userId, 'triggerNo' => 2]);
36204        }
36205
36206
36207        // campaign master trigger 5 
36208        if (strtoupper($data['result']) == 'OK') {
36209            $this->retrial_confiscate_coins([
36210                'formType' => $formType,
36211                'paymentPlanId' => $paymentPlanId,
36212                'userId' => $userId
36213            ]);
36214        }
36215
36216        // - NJ-18780 : lite plan
36217        if (
36218            strtoupper($data['result']) == 'OK' &&
36219            $formType == Configure::read('payment_lite_credit_monthly_payment') && 
36220            in_array($userData['User']['payment_plan_id'], Configure::read('lite_payment_plans'))
36221        ) {
36222            // confisacate and give monthly coin
36223
36224                // - fetch users mc coins
36225                $_monthlyPoints = $this->UsersPoint->getCurrentUserMCPoint($userId); //  mc coins
36226                $_dateNow = date('Y-m-d H:i:s');
36227                $_updateMemo = "";
36228
36229                if ((int) $_monthlyPoints > 0) {
36230                    $_confiscateParams = array(
36231                        'userId' => $userId,
36232                        'point' => $_monthlyPoints,
36233                        'kbn' => 18, // Administrator Change/Minus
36234                        'coinType' => 3
36235                    );
36236
36237                    $conficateLitePoints = $this->UsersPoint->confiscateUserLitePoints($_confiscateParams);
36238
36239                    if ($conficateLitePoints) {
36240                        $_updateMemo = $_updateMemo . "\n {$_dateNow} (Previous Coins (MC)【Confiscated】 : {$_monthlyPoints}. )";
36241                    }
36242                }
36243
36244                $_doneConfiscatePoints = ClassRegistry::init('UsersPointHistory')->confiscateUserLitePointsCoinBox($userId);
36245
36246                // update user memo 
36247                $_currentUser = $this->User->read(array('id','memo','next_charge_date'), $userId);
36248                $_nxtChargeDate = $_currentUser['User']['next_charge_date'];
36249                    
36250                // - set to add monthly coin
36251                $_pointParams = array(
36252                    'userId' => $userId,
36253                    'point' => Configure::read('lite_plan_monthly_coin'),
36254                    'kbn' => Configure::read('lite_plan_bonus_kbn'), // 
36255                    'kbnType' => 1, // add coin
36256                    'coinType' => 3, // mc coin
36257                    'dateExpiration' => $_nxtChargeDate,
36258                    'coinFailMessage' => Configure::read('coin.failed.membership')
36259                );
36260            
36261                // add user's points 
36262                $giveLitePoints = $this->UsersPoint->performPointTransaction($_pointParams);
36263
36264                if ($giveLitePoints) {
36265                    $_coins = Configure::read('lite_plan_monthly_coin');
36266                    $_updateMemo = $_updateMemo . "\n {$_dateNow} | Light Plan Bonus Coins (MC): {$_coins}";
36267                }
36268
36269        
36270                $_currentUserMemo = $_currentUser['User']['memo'];
36271
36272                if (!empty($_updateMemo)) {
36273                    $_updateMemo = $_updateMemo . "\n" . $_currentUserMemo;
36274                    $this->User->clear();
36275                    $this->User->set(array('id' => $userId,'memo' => $_currentUserMemo));
36276                    $this->User->save();
36277                }
36278        }
36279
36280        // send event to adjust
36281        if ($kbResult) {
36282            $adjustParams = array(
36283                'formType' => $formType,
36284                'statusBefore' => isset($ptPaymentParams['statusBefore']) ? $ptPaymentParams['statusBefore'] : null,
36285                'userId' => $userId,
36286                'idfa' => $userData['User']['idfa']
36287            );
36288            UserTable::sendEventToAdjust($adjustParams);
36289        }
36290
36291        //NJ-23626 continuing plan campaign
36292        if ((strtoupper($data['result']) == 'OK' || !empty($ptPaymentParams['coupon_used'])) && in_array($formType, array(Configure::read('payment_credit_retry'), Configure::read('payment_credit_monthly_payment')))){
36293            ClassRegistry::init('CampaignSettingTable')->takingLessonAndContinuePlan(array('user_id' => $userId, 'type' => 3));
36294        }
36295
36296    }
36297
36298    private function stripe_error_log_set($data = array(), $paymentParams = array()) {
36299        // set the variables
36300        $userId = isset($data['user_id']) ? $data['user_id'] : 0;
36301        $money = isset($paymentParams['paymentAmount']) ? $paymentParams['paymentAmount'] : 0;
36302        $sendId = isset($data['sendid']) ? $data['sendid'] : 0;
36303        $cardCompany = isset($data['metadata']['card_company']) ? $data['metadata']['card_company'] : Configure::read('card_company.stripe.apple');
36304        $formType = isset($data['formType']) ? $data['formType'] : 0;
36305        $result = array();
36306
36307        if ($userId && !$sendId) {
36308            $sendId = $userId;
36309        } elseif ($sendId && !$userId) {
36310            $userId = $sendId;
36311        }
36312
36313        $paymentType = isset($paymentParams['paymentType']) ? $paymentParams['paymentType'] : null;
36314        $priceId = isset($paymentParams['priceId']) ? $paymentParams['priceId'] : null;
36315        $paymentId = isset($paymentParams['paymentPlanId']) ? $paymentParams['paymentPlanId'] : null;
36316        $currencyCode = isset($paymentParams['currencyCode']) ? $paymentParams['currencyCode'] : Configure::read('currency_jpy');
36317        $discounted_amount = isset($paymentParams['discounted_amount']) ? $paymentParams['discounted_amount'] : 0;
36318
36319        // Check receivable type
36320        $cronDateRun = date("Y-m-d H:i:s");
36321        $receivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun);
36322        $appreciationReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('appreciation_data.payment_element_type'));
36323        $liveReceivable = $this->PaymentReceivable->computeReceivableReservationPayment($userId, $cronDateRun, Configure::read('payment_element_type.live'));
36324        $receivableFormTypeArr = array( Configure::read('payment_credit_receivable') );
36325        
36326        if( in_array( $formType, $receivableFormTypeArr ) ) {
36327            // Appreciation 
36328            if( $appreciationReceivable > 0 ) {
36329                $this->Payment->create();
36330                $this->Payment->set(array(
36331                    'user_id' => $userId,
36332                    'type_id' => 1,
36333                    'pay_kbn' => 1,
36334                    'form_type' => Configure::read('payment_credit_appreciation_receivable'),
36335                    'reference_id' => $sendId,
36336                    'amount' => $appreciationReceivable,
36337                    'card_company' => $cardCompany,
36338                    'param1' => json_encode($data),
36339                    'param2' => "error:" . $data['error_code'],
36340                    'currency_code' => $currencyCode,
36341                    'price_id' => $priceId,
36342                    'payment_id' => $paymentId,
36343                    'payment_type' => $paymentType,
36344                    'discounted_amount' => $discounted_amount
36345                ));
36346                $result[$formType][] = $this->Payment->save();
36347            }
36348
36349            // Live receivable 
36350            if( $liveReceivable > 0 ) {
36351                $this->Payment->create();
36352                $this->Payment->set(array(
36353                    'user_id' => $userId,
36354                    'type_id' => 1,
36355                    'pay_kbn' => 1,
36356                    'form_type' => Configure::read('payment_live_lesson_receivable'),
36357                    'reference_id' => $sendId,
36358                    'amount' => $liveReceivable,
36359                    'card_company' => $cardCompany,
36360                    'param1' => json_encode($data),
36361                    'param2' => "error:" . $data['error_code'],
36362                    'currency_code' => $currencyCode,
36363                    'price_id' => $priceId,
36364                    'payment_id' => $paymentId,
36365                    'payment_type' => $paymentType,
36366                    'discounted_amount' => $discounted_amount
36367                ));
36368                $res = $this->Payment->save();
36369
36370                if (!$res) {
36371                    CakeLog::debug(__METHOD__ . 'Error : saving live receivable -> params' . json_encode([$data, $paymentParams]));
36372                }
36373                $result[$formType][] = $res;
36374            }        
36375
36376            // Reservation
36377            if( $receivable > 0 ) {
36378                $this->Payment->create();
36379                $this->Payment->set(array(
36380                    'user_id' => $userId,
36381                    'type_id' => 1,
36382                    'pay_kbn' => 1,
36383                    'form_type' => Configure::read('payment_credit_receivable'),
36384                    'reference_id' => $sendId,
36385                    'amount' => $receivable,
36386                    'card_company' => $cardCompany,
36387                    'param1' => json_encode($data),
36388                    'param2' => "error:" . $data['error_code'],
36389                    'currency_code' => $currencyCode,
36390                    'price_id' => $priceId,
36391                    'payment_id' => $paymentId,
36392                    'payment_type' => $paymentType,
36393                    'discounted_amount' => $discounted_amount
36394                ));
36395                $result[$formType][] = $this->Payment->save();
36396            }
36397
36398        } else {
36399            if( $money > 0 ) {
36400                // save new payment row
36401                $this->Payment->create();
36402                $this->Payment->set(array(
36403                        'user_id' => $userId,
36404                        'type_id' => 1,
36405                        'pay_kbn' => 1,
36406                        'form_type' => $formType,
36407                        'reference_id' => $sendId,
36408                        'amount' => $money,
36409                        'card_company' => $cardCompany,
36410                        'param1' => json_encode($data),
36411                        'param2' => "error:" . $data['error_code'],
36412                        'currency_code' => $currencyCode,
36413                        'price_id' => $priceId,
36414                        'payment_id' => $paymentId,
36415                        'payment_type' => $paymentType,
36416                        'discounted_amount' => $discounted_amount
36417                ));
36418
36419                $result[$formType] = $this->Payment->save();
36420
36421                $annualDiscountOption = isset($paymentParams['annualDiscountOption']) ? $paymentParams['annualDiscountOption'] : [];
36422                // check if user plan has annual discount option
36423                if ($annualDiscountOption) {
36424                    // set data for discount option settlement history
36425                    $doshData = [
36426                        'user_id' => $userId,
36427                        'discount_option_term_id' => $annualDiscountOption['discount_option_term_id'],
36428                        'discount_option_id' => $annualDiscountOption['discount_option_id'],
36429                        'payment_id' => $this->Payment->id,
36430                        'discount_option_price_id' => $annualDiscountOption['discount_option_price_id'],
36431                        'payment_id' => $this->Payment->id,
36432                        'event' => $annualDiscountOption['dosh_event'],
36433                        'amount' => $annualDiscountOption['amount'],
36434                        'currency_code' => $currencyCode,
36435                        'type' => isset($annualDiscountOption['dosh_type']) ? $annualDiscountOption['dosh_type'] : null,
36436                        'status' => $annualDiscountOption['dosh_status'],
36437                        'settlement_status' => 0 // failed
36438                    ];
36439
36440                    // create discount option settlement history
36441                    if (!$res = $this->DiscountOptionsSettlementHistory->createHistory($doshData)) {
36442                    }
36443
36444                    $result[$formType][] = $res;
36445                }
36446            }
36447        }
36448    
36449        return $result;
36450        
36451    }
36452
36453
36454
36455    private function slackStripeErrorPostMsg($type = '', $line = '', $method = '', $userId = '', $failMessage='', $debugData = array(), $moreDebugData = array()) {
36456        $mySlack = new mySlack();
36457        $mySlack->channel = myTools::checkChannel("#nc-settlement", "#nc-settlement-dev");
36458        $mySlack->username = "NC Stripe Payment Failed";
36459        $mySlack->text = "```";
36460        $mySlack->text .= "ROLLBACK TYPE:\n";
36461        $mySlack->text .= $type . "\n\n";
36462        $mySlack->text .= "LINE NUMBER:\n";
36463        $mySlack->text .= $line . "\n\n";
36464        $mySlack->text .= "METHOD:\n";
36465        $mySlack->text .= $method . "\n\n";
36466        $mySlack->text .= "USER ID:\n";
36467        $mySlack->text .= $userId . "\n\n";
36468        $mySlack->text .= "KICKBACK URL:\n";
36469        $mySlack->text .= $_SERVER['REQUEST_URI'] . "\n\n";
36470        $mySlack->text .= "EC2 INSTANCE ID:\n";
36471        $mySlack->text .= exec('ec2-metadata -i') . "\n\n";
36472        $mySlack->text .= "REASON OF FAILURE:\n";
36473        $mySlack->text .= date("Y-m-d H:i:s") . " " . $failMessage."\n";
36474        $mySlack->text .= json_encode($debugData);
36475        if (!empty($moreDebugData)) {
36476            $mySlack->text .= "\n" . json_encode($moreDebugData);
36477        }
36478        $mySlack->text .= "```";
36479        $mySlack->sendSlack();
36480    }
36481
36482
36483    public function getStripeHostedPage() {
36484        $this->layout = '';
36485        $logFileName = isset($this->request->data['logFileName']) ? $this->request->data['logFileName'] : 'debug';
36486
36487        if ($this->request->is('post')) {
36488            $postData = $this->request->data;
36489
36490            // throw exception if there is/are missing parameter(s)
36491            if (
36492                !isset($postData['logFileName']) ||
36493                !isset($postData['apiToken']) ||
36494                !isset($postData['formType']) ||
36495                !isset($postData['successUrl']) ||
36496                !isset($postData['paymentMethodType']) ||
36497                !isset($postData['memKeyError']) ||
36498                !isset($postData['referrer']) ||
36499                (
36500                    empty(trim($postData['apiToken'])) &&
36501                    $postData['apiToken'] !== 0 &&
36502                    $postData['apiToken'] !== '0'
36503                )
36504            ) {
36505                $this->log(__METHOD__ . ' Missing parameters. post data --> ' . json_encode($postData), $logFileName);
36506                throw new BadRequestException("Missing parameter(s).");
36507            }
36508
36509            // set variables
36510            $apiToken = $postData['apiToken'];
36511            $formType = $postData['formType'];
36512            $successUrl = urldecode($postData['successUrl']);
36513            $paymentMethodType = $postData['paymentMethodType'];
36514            $nominalAmountArr = Configure::read('stripe.nominal_amount');
36515            $memKeyError = $postData['memKeyError'];
36516            $referrer = $postData['referrer'];
36517            $status = 0; // default pending
36518            $currencyExponents = Configure::read('stripe.currency_exponents');
36519            $exponent = $currencyExponents[$currencyCode];
36520
36521            $userParams = array(
36522                'fields' => array(
36523                    'User.id',
36524                    'User.email',
36525                    'User.nickname',
36526                    'User.card_token',
36527                    'User.charge_flg',
36528                    'User.fail_flg',
36529                    'User.currency_code',
36530                    'User.payment_plan_id',
36531                    'User.price_id',
36532                    'User.double_check_flg',
36533                    'User.status',
36534                    'User.complimentary_code',
36535                    'User.card_company',
36536                    'User.phone_number',
36537                    'PaymentPlanPrice.amount'
36538            ),
36539                'apiToken' => $apiToken
36540            );
36541
36542            // throw exception if api token not exist
36543            if (!$userData = $this->User->getWPMobappUserData($userParams)) {
36544                $this->log(__METHOD__ . ' User api token does not exist. User params --> ' . json_encode($userParams), $logFileName);
36545                throw new InternalErrorException("User api token does not exist.");
36546            }
36547
36548            $userCurrencyCode = $userData['User']['currency_code'];
36549            $complimentaryCode = $userData['User']['complimentary_code'];
36550
36551            // NC-9168: override currency if worldpay card auth and JPY currency
36552            $expectedUserCurrency = $this->allowedCurrencies[$this->localizeDir];
36553            if (isset($postData['ncTerminalType']) && $postData['ncTerminalType'] == 1 &&
36554                $formType == Configure::read('payment_credit_authentication') && $userData['User']['currency_code'] != $expectedUserCurrency) {
36555                // Get localized language equivalent currency code
36556                if (
36557                    isset($this->localizeDir) && 
36558                    in_array($this->localizeDir, array_keys($this->allowedCurrencies)) &&
36559                    // do not update currency_code if user account has complimentary code
36560                    empty($complimentaryCode)
36561                ) {
36562                    $userCurrencyCode = $this->allowedCurrencies[$this->localizeDir];
36563                    // NC-9629: do not override if JPY
36564                    if ($userCurrencyCode == Configure::read('default.user_currency')) {
36565                    } else {
36566                        $this->User->validate = array();
36567                        $this->User->read(array('currency_code'), $userData['User']['id']);
36568                        $this->User->set(array('currency_code' => $userCurrencyCode));
36569                        $this->User->save();
36570                    }
36571                }
36572            }
36573
36574            // set variables
36575            $paymentPlanPriceAmount = $userData['PaymentPlanPrice']['amount'];
36576            $userData = $userData['User'];
36577            $currencyCode = $userCurrencyCode;
36578            $paymentPlanId = $userData['payment_plan_id'];
36579            $priceId = $userData['price_id'];
36580            $userId = $userData['id'];
36581            $preToken = $userData['card_token'];
36582            $discounted_amount = isset($userData['discounted_amount']) ?? 0;
36583            $totalAmountArr = myTools::wpGetAmount($exponent, $nominalAmountArr[$currencyCode]);
36584            $ncPaymentAmount = 0;
36585            $stripePaymentAmount = $totalAmountArr['wpAmount'];
36586
36587
36588            // get payment method (debit or credit)
36589            $paymentMethod = 'stripe';
36590
36591            switch ($formType) {
36592                case Configure::read('payment_credit_authentication'):
36593                    $tokenReason = 'Payment Credit Registration';
36594                    if (!isset($priceId)) {
36595                        // get payment data
36596                        $paymentData = $this->PaymentPlanPrice->getPaymentData(array(
36597                            'currencyCode' => $currencyCode,
36598                            'paymentPlanId' => Configure::read('payment_plans.free_trial'),
36599                            'logFileName' => $logFileName
36600                        ));
36601
36602                        // throw error exception if does not exist
36603                        if (!$paymentData) {
36604                            throw new InternalErrorException("Payment plan does not exist.");
36605                        }
36606
36607                        $priceId = $paymentData['priceId'];
36608                    }
36609                    $paymentPlanId = Configure::read('payment_plans.free_trial');
36610                    break;
36611                case Configure::read('payment_credit_change'):
36612                    if (!isset($priceId) || !isset($paymentPlanId)) {
36613                        throw new InternalErrorException("Price id or payment plan id is/are empty.");
36614                    }
36615
36616                    // add reserve payment amount
36617                    $receivablePayment = $this->PaymentReceivable->computeReceivableReservationPayment($userId);
36618
36619                    // add appreciation lesson amount
36620                    $receivablePayment += $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.appreciation'));
36621
36622                    // add live lesson amount
36623                    $receivablePayment += $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.live'));
36624
36625                    // change payment method type to payment, if has receivable payment
36626                    if ($receivablePayment > 0) {
36627                        $paymentMethodType = $paymentMethod . '_payment';
36628                        $wpPaymentAmount = $ncPaymentAmount = $receivablePayment;
36629                    }
36630                    
36631                    $tokenReason = 'Payment Credit Change';
36632                    break;
36633                case Configure::read('payment_credit_retry'):
36634                    // get payment data
36635                    if (!$paymentData = $this->getRetryPaymentData($userData, $logFileName)) {
36636                        throw new InternalErrorException("Payment plan does not exist.");
36637                    }
36638
36639                    $stripePaymentAmount = $paymentData['amount'];
36640                    $priceId = $paymentData['priceId'];
36641                    $paymentPlanId = $paymentData['paymentPlanId'];
36642                    
36643                    // NJ-47740 - get monthly reqeust coupon discount
36644                    $coupon = $this->UsersCouponV1->getCouponUseRequest(array(
36645                        'userId' => $userId,
36646                        'kbn' => Configure::read('coupon_kbn.monthly_settlement')
36647                    ));
36648                    
36649                    if (!empty($coupon['amount']) && !empty($coupon['grp_id'])) {
36650                        
36651                        if ($coupon['amount'] >= $stripePaymentAmount) {
36652                            $userData['monthlyDiscount'] = $stripePaymentAmount;
36653                            $stripePaymentAmount = 0;
36654                        } else {
36655                            $stripePaymentAmount -= $userData['monthlyDiscount'] = $coupon['amount'];
36656                        }
36657                        $userData['monthly_grp_id'] = $coupon['grp_id'];
36658                    }
36659
36660                    // add reserve payment amount
36661                    $stripePaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment($userId);
36662
36663                    // add appreciation lesson amount
36664                    $stripePaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.appreciation'));
36665
36666                    // add live lesson amount
36667                    $stripePaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.live'));
36668
36669                    $ncPaymentAmount = $stripePaymentAmount;
36670
36671                    // change payment method type to auth if amount to be paid in is equal to 0
36672                    if ($stripePaymentAmount == 0) {
36673                        $paymentMethodType = $paymentMethod . '_auth';
36674                        $stripePaymentAmount = $nominalAmountArr[$currencyCode];
36675                    }
36676
36677                    $tokenReason = 'Payment Credit Retry';
36678                    break;
36679                case Configure::read('payment_credit_force_charge'):
36680                    // get payment data
36681                    $paymentData = $this->PaymentPlanPrice->getPaymentData(array(
36682                        'currencyCode' => $currencyCode,
36683                        'paymentPlanId' => Configure::read('payment_plans.premium_plan'),
36684                        'logFileName' => $logFileName
36685                    ));
36686
36687                    // throw error exception if does not exist
36688                    if (!$paymentData) {
36689                        throw new InternalErrorException("Payment plan does not exist.");
36690                    }
36691
36692                    $stripePaymentAmount = $paymentData['amount'];
36693                    $priceId = $paymentData['priceId'];
36694                    $paymentPlanId = $paymentData['paymentPlanId'];
36695
36696                    // add reserve payment amount
36697                    $stripePaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment($userId);
36698
36699                    // add live lesson payment amount
36700                    $stripePaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment( $userId, false, Configure::read('appreciation_data.payment_element_type') );
36701
36702                    // add live lesson payment amount
36703                    $stripePaymentAmount += $this->PaymentReceivable->computeReceivableReservationPayment($userId, false, Configure::read('payment_element_type.live'));                    
36704
36705                    $ncPaymentAmount = $stripePaymentAmount;
36706
36707                    // change payment method type to auth if amount is  equal to 0
36708                    if ($stripePaymentAmount == 0) {
36709                        $paymentMethodType = $paymentMethod . '_auth';
36710                        $totalAmountArr = myTools::wpGetAmount($exponent, $nominalAmountArr[$currencyCode]);
36711                        $stripePaymentAmount = $totalAmountArr['wpAmount'];
36712                    } else {
36713                        $totalAmountArr = myTools::wpGetAmount($exponent, $stripePaymentAmount);
36714                        $ncPaymentAmount = $totalAmountArr['ncAmount'];
36715                        $stripePaymentAmount = $totalAmountArr['wpAmount'];
36716                    }
36717
36718                    $tokenReason = 'Payment Credit Charge';
36719                    break;
36720            }
36721
36722            $orderNumber = myTools::generateOrderCode($userId);
36723
36724            // before coupon settlement amount deduction
36725            $beforeCouponSettlementAmount = $ncPaymentAmount;
36726
36727            // NJ-32737
36728            $couponData = $this->Session->read('apply_coupon_usage_data');
36729
36730            $membershipStatusIndex = UserTable::getStudentMembershipStatus($userId);
36731            if (in_array($membershipStatusIndex, Configure::read('allow_coupon.settlement')) &&
36732                isset($formType) &&
36733                in_array($formType, Configure::read('allow_coupon.settlement_form_type'))
36734            ) {
36735                // confiscate the coupon pending request when student is re-enrolled
36736                $res_confiscate = $this->UsersCouponV1->confiscateAllCoupon(array(
36737                    'userId' => $userId,
36738                    'action_type' => 1 // only the pending request will be confiscated
36739                ));
36740                
36741                if (!$res_confiscate) {
36742                    $this->log(__METHOD__ . ' Failed to confiscate coupon pending request. User id --> ' . $userId, $logFileName);
36743                }
36744
36745                if (isset($couponData['useCouponAmount']) && $couponData['useCouponAmount'] > 0) {
36746                    if ($stripePaymentAmount >= $couponData['useCouponAmount']) {
36747                        $stripePaymentAmount -= $couponData['useCouponAmount'];
36748                        $ncPaymentAmount -= $couponData['useCouponAmount'];
36749                    } else {
36750                        $stripePaymentAmount = 0;
36751                        $ncPaymentAmount = 0;
36752                    }
36753
36754                    // change niminal amount if amount is  equal to 0
36755                    if ($stripePaymentAmount == 0) {
36756                        $stripePaymentAmount = $nominalAmountArr[$currencyCode];
36757                    }
36758
36759                    $couponUseSettlement = $couponData;
36760                }
36761            }
36762            // NJ-32737-end
36763
36764            // get total amount with checking currency exponent
36765            $totalAmountArr = myTools::wpGetAmount($exponent, $stripePaymentAmount);
36766            $stripePaymentAmount = $totalAmountArr['wpAmount'];
36767
36768
36769            $paymentParams = array(
36770                'currencyCode' => $currencyCode,
36771                'formType' => $formType,
36772                'logFileName' => $logFileName,
36773                'remoteAddress' => $_SERVER["REMOTE_ADDR"],
36774                'cardToken' => isset($userData['card_token']) ? $userData['card_token'] : null,
36775                'newCard' => true,
36776                'stripePaymentAmount' => $stripePaymentAmount,
36777                'paymentAmount' => $ncPaymentAmount,
36778                'priceId' => $priceId,
36779                'paymentPlanId' => $paymentPlanId,
36780                'paymentType' => Configure::read('payment_types.payment_plan')
36781            );
36782
36783            if (!empty($couponUseSettlement)) {
36784                $paymentParams['couponUseSettlement'] = $couponUseSettlement;
36785            }
36786            
36787            if (!empty($coupon) && isset($formType) && $formType == Configure::read('payment_credit_retry') && !empty($userData['monthlyDiscount']) && !empty($userData['monthly_grp_id'])) {
36788                $paymentParams['discounted_amount'] = $userData['monthlyDiscount'];
36789                $paymentParams['monthlyDiscount'] = $userData['monthlyDiscount'];
36790                $paymentParams['monthly_grp_id'] = $userData['monthly_grp_id'];
36791            }
36792
36793            if (isset($postData['userRegister']) && $postData['userRegister']) {
36794                $paymentParams['userRegister'] = true;
36795            }
36796
36797            // NJ-42971: free trial checker
36798            $notFreeTrial = true;
36799
36800            if ($formType != Configure::read('payment_credit_change')) {
36801                $membershipTypes = UserTable::getEngMembershipTypeData();
36802                $statusAfter = $membershipTypes[1]; // premium plan paid
36803
36804                /* -- get before status -- */
36805                if ($this->memcache->get('com_plan_user_' . $userId) && $userData && $userData['payment_plan_id'] == Configure::read('payment_plans.complimentary_plan')) {
36806                    $statusBefore = $membershipTypes[15]; // complimentary code
36807                    $paymentParams['bonusCoinFlg'] = 1;
36808                    $paymentParams['updateFirstChargeDate'] = true;
36809                } elseif ($userData['charge_flg'] == 0) {
36810                    // failed settlement
36811                    if ($userData['fail_flg'] == 1) {
36812                        $statusBefore = $membershipTypes[5];
36813                    // trial again
36814                    } elseif ($userData['fail_flg'] == 0 && $userData['double_check_flg'] == 1) {
36815                        $statusBefore = $membershipTypes[13];
36816                        $notFreeTrial = false;
36817                    // unsubscribed
36818                    } elseif ($userData['fail_flg'] == 0 && $userData['double_check_flg'] == 2) {
36819                        $statusBefore = $membershipTypes[12];
36820                    // temporary
36821                    } elseif ($userData['status'] == 0) {
36822                        $statusBefore = $membershipTypes[6];
36823                        $statusAfter = $membershipTypes[2]; // premium plan free
36824                    } else {
36825                        $statusBefore = null;
36826                    }
36827                }
36828
36829                if (isset($statusBefore)) {
36830                    $user = new UserTable($userData);
36831                    $membershipTypeIndex = $user->getMembershipTypeIndex();
36832
36833                    if ($membershipTypeIndex == 13) {
36834                        $statusBefore = $membershipTypes[13];
36835                        $paymentParams['userRegister'] = true;
36836                        $notFreeTrial = false;
36837                        $statusAfter = $membershipTypes[2];
36838                    }
36839
36840                    // get platform use
36841                    $platform = myTools::mobappDetectPlatform();
36842                    $paymentParams['platform'] = $platform == Configure::read('platform.splp') ? Configure::read('platform.pclp') : $platform;
36843                    $paymentParams['statusBefore'] = $statusBefore;
36844                    $paymentParams['statusAfter'] = $statusAfter;
36845
36846                    $user = new UserTable($userData);
36847                    $membershipTypeIndex = $user->getMembershipTypeIndex();
36848
36849                    if ($membershipTypeIndex == 13) {
36850                        $paymentParams['userRegister'] = true;
36851                    }
36852                }
36853            }
36854
36855            $ptParams = array(
36856                'user_id' => $userId,
36857                'payment_hash' => $orderNumber,
36858                'status' => $status,
36859                'payment_params' => json_encode($paymentParams),
36860                'course_id' => Configure::read("credit.course_id")
36861            );
36862
36863            // throw exception if failed to save payment transaction
36864            if (!$pt = $this->PaymentTransaction->setWPPaymentTransaction($ptParams)) {
36865                $this->log(__METHOD__ .' Failed to save payment transaction. update data --> ' . json_encode($result), $logFileName);
36866                throw new InternalErrorException("Failed to save payment transaction.");
36867            }
36868
36869            $this->Session->write('wp_coupon_settlement_payment', [
36870                'payment_hash' => $pt['payment_hash'],
36871                'payment_amount' => $beforeCouponSettlementAmount // set before coupon settlement amount
36872            ]);
36873
36874            $this->set('logFileName', $logFileName);
36875            $this->set('apiToken', $apiToken);
36876            $this->set('orderNumber', $orderNumber);
36877            $this->set('userId', $userId);
36878            $this->set('salesSettled', $auth ? 'false' : 'true');
36879            $this->set('stripePaymentAmount', $stripePaymentAmount);
36880            $this->set('ncPaymentAmount', $ncPaymentAmount);
36881            $this->set('transactionOptions', $auth);
36882            $this->set('nc_terminal_type', isset($postData['ncTerminalType']) ? $postData['ncTerminalType'] : 0);
36883            $this->set('formType', $formType);
36884            $this->set('memKeyError', 'card_regist_error_'.$apiToken);
36885            $this->set('referrer', $postData['referrer']);
36886            $this->set('successUrl', $successUrl);
36887            $this->set('userRegister', true);
36888            $this->set('ptID', $pt['id']);
36889            $this->set('preToken', $preToken);
36890        } else {
36891            throw new MethodNotAllowedException("Method used is not POST.");
36892        }
36893
36894        $this->render('/Elements/mobapp/stripe_get_hosted_page');
36895    }
36896
36897
36898    private function sendStripeResponseSlackMessage($params) {
36899        // - add response
36900        $mySlack = new mySlack();
36901        $mySlack->allow_test_channel = true;
36902        $mySlack->channel = myTools::checkChannel("#nj-agpay-results", "#nj-agpay-results");
36903        $mySlack->username = "STRIPE PAYMENT EVENT";
36904        $mySlack->link_names = true;
36905        $mySlack->token = "xoxb-392902820692-6499139810404-RHHGc6Z5ZB9o2KkiGhzTTtlQ";
36906        $mySlack->text = "```";
36907        $mySlack->text .= "user_id: " . $params['userId'] . "\n\n";
36908        if(isset($params['payment_hash']) && $params['payment_hash']) {
36909            $mySlack->text .= "payment_hash: " . $params['paymentHash'] ."\n\n";
36910        }
36911        $mySlack->text .= "action: " . $params['action'] ."\n\n";
36912        $mySlack->text .= "request: " . json_encode($params['request']) ."\n\n";
36913        $mySlack->text .= "response: " . json_encode($params['response']) ."\n\n";
36914        if(isset($params['error_msg']) && $params['error_msg']) {
36915            $mySlack->text .= "error: " . $params['error_msg'] ."\n\n";
36916        }
36917        $mySlack->text .= "```";
36918        $mySlack->postMessage();
36919    }
36920
36921    /**
36922     * NC-62324: Update user Token
36923     * @param array $params
36924     * @return array $res
36925     */
36926    private function updateUserToken($params = array()) {
36927        $result = wpPaymentService::updateUserToken($params['updateTokenParams']);
36928        $deleteTokenResultJson = json_encode($result); // ~ NJ-69126 [Warning] Undefined variable $deleteTokenResultJson
36929        $updateToken = isset($result['paymentService']['reply']['ok']['updateTokenReceived']) ? true : false;
36930
36931        // log if failed to delete token in wp
36932        if (!$updateToken) {
36933            $this->log(__METHOD__ . ' Failed to udpate user wp card token. params --> ' . json_encode($params['updateTokenParams']) . ", error(s) --> " . $deleteTokenResultJson .' | kickback data --> ' . $params['dataJson'], $params['logFileName']);
36934        }
36935
36936        return $result;
36937    }
36938}